-
Notifications
You must be signed in to change notification settings - Fork 0
/
parsiuntimai.py
179 lines (144 loc) · 7.77 KB
/
parsiuntimai.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""
Bendrieji įrankiai parsisiuntimams iš interneto
(c) 2024 Mindaugas Baranauskas
---
Ši programa yra laisva. Jūs galite ją platinti ir/arba modifikuoti
remdamiesi Free Software Foundation paskelbtomis GNU Bendrosios
Viešosios licencijos sąlygomis: 3 licencijos versija, arba (savo
nuožiūra) bet kuria vėlesne versija.
Ši programa platinama su viltimi, kad ji bus naudinga, bet BE JOKIOS
GARANTIJOS; taip pat nesuteikiama jokia numanoma garantija dėl TINKAMUMO
PARDUOTI ar PANAUDOTI TAM TIKRAM TIKSLU. Daugiau informacijos galite
rasti pačioje GNU Bendrojoje Viešojoje licencijoje.
Jūs kartu su šia programa turėjote gauti ir GNU Bendrosios Viešosios
licencijos kopiją; jei ne - žr. <https://www.gnu.org/licenses/>.
---
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
import platform
import requests
from bs4 import BeautifulSoup # reikalingas beautifulsoup4 paketas
from urllib.parse import unquote # url adresuose esančių simbolių kodų pakeitimui į įprastus
def gauti_internetu(url, atsakymo_tipas='content', detaliai=False):
"""
Pagal pateiktą URL adresą grąžina internetinio puslapio turinį (HTML kodą) kaip kintamąjį (neįrašo į diską)
"""
# pvz., gali parsiųsti
# https://archyvas.meteo.lt/?station=vilniaus-ams&start_date=2014-01-01&end_date=2014-12-31&meteo-form=Rodyti
# Naršylės imitavimas priklausomai nuo operacinės sistemos
operacine_sist = platform.system() # Linux, Windows, Darwin (Mac)
if operacine_sist == 'Windows':
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0'}
elif operacine_sist == 'Linux':
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:115.0) Gecko/20100101 Firefox/115.0'}
elif operacine_sist == 'Darwin': # MAC OS
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.4; rv:115.0) Gecko/20100101 Firefox/115.0'}
else:
headers = None
# Pats puslapio parsisiuntimas
try:
atsakas = requests.get(url, headers=headers, stream=True) # stream dėl didesnių rinkmenų - srautas dalinamas
except requests.exceptions.ConnectionError:
print("Nepavyko pasiekti interneto. Patikrinkite ryšį.")
return None
# Atsakymo tikrinimas
if atsakas.status_code == 200:
if detaliai:
print(f' - Pavyko pasiekti {url}')
if atsakymo_tipas in ['text', 'txt', 'tekstas']:
return atsakas.text
if atsakymo_tipas in ['content', 'turinys']:
return atsakas.content
else:
return atsakas
else:
print(f' - Nepavyko pasiekti {url}: {atsakas.status_code}')
if detaliai:
print(BeautifulSoup(atsakas.text, 'html.parser').text.strip())
return None
def parsisiųsti_rinkmeną(url, vietinis_kelias=None, detaliai=True):
"""
Parsisiųsti dokumentą iš interneto ir jį išsaugoti diske
:param url:
:param vietinis_kelias:
:param detaliai:
:return: Grąžina pilną kelią, kur dokumentas įrašytas
"""
try:
vardas = rinkmenos_vardas_pagal_url(url) # parsisiunčiamos rinkmenos vardas
# jei nenurodytas, atspėti rikmenos vardą saugojimui pagal url
if not vietinis_kelias: # naudotojas nenurodė kaip įrašyti, tad pavadinimą parinkti automatiškai
vietinis_kelias = vardas
# sukurti katalogą, jei nėra
katalogas = os.path.abspath(os.path.dirname(vietinis_kelias))
if katalogas and not os.path.exists(katalogas): # jei katalogo nėra
os.makedirs(katalogas) # sukurti katalogą
if os.path.isdir(vietinis_kelias): # kelias yra tik katalogas
vietinis_kelias = os.path.join(vietinis_kelias, vardas) # prie kelio pridėti pavadinimą
# patikslinti kelią saugojimui
vietinis_kelias = os.path.abspath(vietinis_kelias)
# parsisiųti dokumento turinį
turinys = gauti_internetu(url, atsakymo_tipas='content')
if not turinys: # Jei nepavyko parsisiųsti
return None
# įrašyti dokumentą
with open(vietinis_kelias, 'wb') as rinkmena:
rinkmena.write(turinys)
if detaliai:
print(' Sėkmingai parsiųsta rinkmena', vardas, 'ir įrašyta į\n ', vietinis_kelias)
return vietinis_kelias # grąžinti kelią, kur įrašyta
except Exception as err:
if detaliai:
print(' Klaida parsisiunčiant „%s“:\n %s' % (url, err))
return None
def išrinkti_nuorodas_iš_puslapio(puslapio_url, lentelės_požymiai=None, nuorodos_tekstas=None):
"""
Iš duombazės aprašo puslapio, kuriame yra lentelė su nuorodomis į duomenis, išrenka tas nuorodas
Įvedimo parametrai:
puslapio_url - duombazės aprašo puslapis su nuorodų lentele
lentelės_požymiai - lentelės unikalios ypatybės, kurios padeda pasirinkti reikiamą lentelę, ypač jei jų kelios
nuorodos_tekstas - tekstas, kuris yra tarp <a> ir </a> HTML kodo dalių
"""
# Patikrinti įvedimo kintamuosius
if not (type(puslapio_url) is str and '://' in puslapio_url): # nėra (teksto ir protokolo)?
print('Pirmasis argumentas turi būti puslapio URL. Netinka pateiktasis: %s' % puslapio_url)
return []
if not (type(nuorodos_tekstas) in [str, type(None)]):
print('Parametras „nuorodos_tekstas“ yra papildomas kriterijus nuorodoms atrinkti. Jis turi būti tekstinis')
return []
# Parsisiųsti HTML puslapį
html_puslapio_turinys = gauti_internetu(puslapio_url, atsakymo_tipas='text') # Gauti HTML kodą kaip tekstą
if not html_puslapio_turinys: # jei nepavyko parsiųsti HTML puslapio
return [] # grąžinti, tuščią sąrašą - jokių nuorodų
# HTML puslapyje rasti lentelę
soup = BeautifulSoup(html_puslapio_turinys, 'html.parser') # inicijuoti html puslapio nagrinėjimą
lentele = soup.find('table', attrs=lentelės_požymiai) # ieškoti lentelės
if not lentele: # jei lentelės rasti nepavyko
return []
# Darbas su lentelės nuorodomis
a_blokai = lentele.find_all('a') # surasti visus nuorodų blokus
if nuorodos_tekstas in [None, '']: # naudotojas nenurodė jokios nuorodų atrankos filtro
nuorodos = [blokas['href'] for blokas in a_blokai] # visos nuorodos (href=), be jokios atrankos
else: # naudotojas nurodė nuorodų atrankos filtrą
nuorodos = [blokas['href'] for blokas in a_blokai if blokas.text.strip() == nuorodos_tekstas] # su atranka
protokolas_ir_domenas = '/'.join(puslapio_url.split('/')[:3]) # prireiks žemiau, jei nuoroda neturės jų
for i, nuoroda in enumerate(nuorodos):
if '://' not in nuoroda: # jei nuoroda neturi protokolo ir domeno
if nuoroda[0] == '/': # nuoroda prasideda /
nuorodos[i] = protokolas_ir_domenas + nuoroda # pridėti protokolą ir domeną pagal pirminį puslapį
else:
nuorodos[i] = '/'.join(puslapio_url.split('/')[:-1]) + '/' + nuoroda # pakeisti pradinio puslapio galą
return nuorodos
def rinkmenos_vardas_pagal_url(url):
url_dalys = [dalis for dalis in (url + '/').split('/') if dalis] # netuščios dalys URL adrese
return unquote(url_dalys[-1])