Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
Següent revisió | Revisió prèvia | ||
webscraping_apache [2022/07/05 18:00] josefina_llaberia creat |
webscraping_apache [2022/08/01 07:05] (actual) lidia_alos [Eines de scraping per a Python] |
||
---|---|---|---|
Línia 1: | Línia 1: | ||
- | ====== | + | ====== |
- | + | ||
- | **Tema** és un tipus... | + | |
+ | **Webscraping** fa referència a les tècniques per a recuperar dades d'una web de manera automatitzada, | ||
+ | i Python és un llenguatge de programació que té llibreries especialitzades que faciliten aquesta | ||
+ | tasca. | ||
{{tag> #FpInfor #Ceti #Ciber #CetiMp03 #CiberMp03 #Asix #AsixMp17 # | {{tag> #FpInfor #Ceti #Ciber #CetiMp03 #CiberMp03 #Asix #AsixMp17 # | ||
Línia 8: | Línia 9: | ||
\\ | \\ | ||
- | ===== Títol 2 ===== | + | ===== Descarregar les imatges d’una web ===== |
- | Descarrega aquest repositori amb un exemple | + | Començarem per un script que es baixa totes les imatges que hi ha una web a partir |
+ | |||
+ | Primer, haurem d’instal·lar la llibreria lxml de Python per el tractament d’html. | ||
+ | |||
+ | Comandes: | ||
+ | $ pip install lxml | ||
+ | |||
+ | Collecting lxml | ||
+ | Downloading lxml-4.9.1-cp310-cp310-win_amd64.whl (3.6 MB) | ||
+ | | ||
+ | Installing collected packages: lxml | ||
+ | Successfully installed lxml-4.9.1 | ||
+ | |||
+ | Script: | ||
+ | import os | ||
+ | import requests | ||
+ | from lxml import html | ||
+ | |||
+ | try: | ||
+ | url = " | ||
+ | response = requests.get(url) | ||
+ | parsed_body = html.fromstring(response.text) | ||
+ | |||
+ | # Usem una expressió xpath per a trobar els tags d' | ||
+ | images_src = parsed_body.xpath("// | ||
+ | num_images = len(images_src) | ||
+ | print(" | ||
+ | |||
+ | # Creem un directori per anar guardant les imatges | ||
+ | nom_domini = url.replace(" | ||
+ | nom_domini = nom_domini.replace(" | ||
+ | nom_directori = " | ||
+ | print(" | ||
+ | os.system(" | ||
+ | |||
+ | for image in images_src: | ||
+ | download = False | ||
+ | if image.startswith(" | ||
+ | downloaded_image = requests.get(image) | ||
+ | download = True | ||
+ | elif image.startswith(" | ||
+ | downloaded_image = requests.get(url + image) | ||
+ | download = True | ||
+ | #else: | ||
+ | # download base64 image | ||
+ | if download: | ||
+ | image_file_name_to_save = nom_directori + "/" | ||
+ | print(image_file_name_to_save) | ||
+ | image_file = open(image_file_name_to_save, | ||
+ | image_file.write(downloaded_image.content) | ||
+ | image_file.close() | ||
+ | |||
+ | except Exception as e: | ||
+ | print(e) | ||
+ | pass | ||
+ | |||
+ | Sortida: | ||
+ | Trobade(s) 16 imatge(s) | ||
+ | Guardant imatges al directori imatges_agora_xtec_cat | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
+ | imatges_agora_xtec_cat/ | ||
- | $ git clone https:// | ||
- | $ cd sqlinjection-php | ||
- | $ docker-compose up -d --build | ||
<WRAP todo> | <WRAP todo> | ||
Exercici: | Exercici: | ||
+ | Adapta l’ script per a obtenir tots els enllaços / links (tag <a>) que hi ha en una plana web a partir de la seva url i els guardi en un fitxer o els imprimeixi per pantalla. | ||
</ | </ | ||
\\ | \\ | ||
- | ===== Títol 3 ===== | + | ===== Obtenir informació d’imatges |
- | **Tem** és ... | + | Amb les imatges baixades, mirarem si tenen informacio |
+ | L’**EXIF** és un estàndard que defineix informació específica relacionada amb una imatge capturada per una càmera digital. | ||
+ | Primer, haurem d’instal·lar la llibreria Pillow de Python pel tractament d’imatges. | ||
+ | |||
+ | Comandes: | ||
+ | $ pip install pillow | ||
+ | | ||
+ | Collecting pillow | ||
+ | Downloading Pillow-9.2.0-cp310-cp310-win_amd64.whl (3.3 MB) | ||
+ | | ||
+ | Installing collected packages: pillow | ||
+ | Successfully installed pillow-9.2.0 | ||
+ | |||
+ | Script: | ||
+ | from PIL import Image | ||
+ | from PIL import ExifTags | ||
+ | | ||
+ | image = Image.open(" | ||
+ | | ||
+ | exif_info = image._getexif() | ||
+ | | ||
+ | for tag, value in exif_info.items(): | ||
+ | decoded = ExifTags.TAGS.get(tag, | ||
+ | print(str(decoded) + ": " + str(value)) | ||
+ | |||
+ | Sortida: | ||
+ | ImageWidth: 6720 | ||
+ | ImageLength: | ||
+ | BitsPerSample: | ||
+ | PhotometricInterpretation: | ||
+ | ResolutionUnit: | ||
+ | ExifOffset: 288 | ||
+ | Make: Canon | ||
+ | Model: Canon EOS 5D Mark IV | ||
+ | Software: Adobe Photoshop CC 2018 (Macintosh) | ||
+ | Orientation: | ||
+ | DateTime: 2022:06:22 11:18:01 | ||
+ | SamplesPerPixel: | ||
+ | XResolution: | ||
+ | YResolution: | ||
+ | ExifVersion: | ||
+ | ShutterSpeedValue: | ||
+ | ApertureValue: | ||
+ | DateTimeOriginal: | ||
+ | DateTimeDigitized: | ||
+ | ExposureBiasValue: | ||
+ | MaxApertureValue: | ||
+ | MeteringMode: | ||
+ | ColorSpace: 65535 | ||
+ | Flash: 16 | ||
+ | FocalLength: | ||
+ | ExifImageWidth: | ||
+ | ExifImageHeight: | ||
+ | SceneCaptureType: | ||
+ | FocalPlaneXResolution: | ||
+ | FocalPlaneYResolution: | ||
+ | OffsetTime: +02:00 | ||
+ | OffsetTimeOriginal: | ||
+ | OffsetTimeDigitized: | ||
+ | SubsecTimeOriginal: | ||
+ | SubsecTimeDigitized: | ||
+ | FocalPlaneResolutionUnit: | ||
+ | ExposureTime: | ||
+ | FNumber: 4.5 | ||
+ | ExposureProgram: | ||
+ | CustomRendered: | ||
+ | ISOSpeedRatings: | ||
+ | ExposureMode: | ||
+ | SensitivityType: | ||
+ | WhiteBalance: | ||
+ | RecommendedExposureIndex: | ||
+ | BodySerialNumber: | ||
+ | LensSpecification: | ||
+ | LensModel: EF70-200mm f/4L USM | ||
+ | LensSerialNumber: | ||
+ | |||
+ | Aquest script és capaç d’obtenir les dades EXIF que hi ha en una foto, així, podem saber la data en que es va fer la foto, la càmara usada, i fins i tot, dades d’ubicació GPS si el dispositiu des de el qual es va fer té aquesta opció. | ||
+ | |||
+ | <WRAP todo> | ||
+ | Exercici: | ||
+ | |||
+ | Investiga les dades de més interès que pot aportar la informació EXIF d’una foto penjada a una web. | ||
+ | </ | ||
+ | |||
+ | <WRAP todo> | ||
+ | Exercici: | ||
+ | |||
+ | Adapta l’ script per a obtenir la info EXIF de totes imatges que hi hagi en un directori. | ||
+ | </ | ||
- | Referències: | ||
- | * Pàgina oficial DVWA: https:// | ||
- | * Versió Docker DVWA: https:// | ||
\\ | \\ | ||
+ | |||
+ | ===== Informació de la construcció d’una web ===== | ||
+ | |||
+ | Una altra informació d’interès que podem capturar d’una web són les capçaleres http i les respostes a errors típics per a saber quins serveis, versions i sistemes operatius hi ha corrent en un servidor. | ||
+ | |||
+ | A continuació, | ||
+ | |||
+ | Instal·lem la llibreria amb les comandes corresponents. | ||
+ | |||
+ | Comandes: | ||
+ | $ pip install builtWith | ||
+ | | ||
+ | Collecting builtWith | ||
+ | Downloading builtwith-1.3.4.tar.gz (34 kB) | ||
+ | Preparing metadata (setup.py) ... done | ||
+ | Collecting six | ||
+ | Downloading six-1.16.0-py2.py3-none-any.whl (11 kB) | ||
+ | Using legacy ' | ||
+ | Installing collected packages: six, builtWith | ||
+ | Running setup.py install for builtWith ... done | ||
+ | Successfully installed builtWith-1.3.4 six-1.16.0 | ||
+ | |||
+ | Script: | ||
+ | >>> | ||
+ | >>> | ||
+ | |||
+ | Sortida: | ||
+ | {' | ||
+ | |||
+ | Provem més pàgines: | ||
+ | >>> | ||
+ | | ||
+ | {' | ||
+ | | ||
+ | >>> | ||
+ | | ||
+ | {' | ||
+ | | ||
+ | >>> | ||
+ | | ||
+ | {' | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== Ocultar la informació de capçaleres http d’Apache web server ===== | ||
+ | |||
+ | Instal·lem una servidor apache en una màquina virtual amb Ubuntu Linux. | ||
+ | |||
+ | Comandes: | ||
+ | $ sudo apt install apache2 | ||
+ | |||
+ | Una vegada instal·lat, | ||
+ | |||
+ | Comanda: | ||
+ | $ curl -I localhost | ||
+ | | ||
+ | HTTP/1.1 200 OK | ||
+ | Date: Tue, 05 Jul 2022 16:54:48 GMT | ||
+ | Server: Apache/ | ||
+ | Last-Modified: | ||
+ | ETag: " | ||
+ | Accept-Ranges: | ||
+ | Content-Length: | ||
+ | Vary: Accept-Encoding | ||
+ | Content-Type: | ||
+ | |||
+ | Veiem que dona informació de la versió d’apache instal·lada i del sistema operatiu. | ||
+ | |||
+ | Aquesta informació també la donarà en una configuració per defecte en escriure una url del servidor que faci referència a una pàgina que no existeix. | ||
+ | |||
+ | {{:: | ||
+ | |||
+ | Per a configurar que no es mostri aquesta informació, | ||
+ | |||
+ | Comandes: | ||
+ | $ sudo nano / | ||
+ | |||
+ | Actualitzar els valors a: | ||
+ | ServerTokens Prod | ||
+ | ServerSignature Off | ||
+ | |||
+ | Reiniciar el servei apache: | ||
+ | sudo systemctl restart apache2 | ||
+ | |||
+ | I provem la informació que retorna després d’aquest canvi de configuració. | ||
+ | |||
+ | Comanda: | ||
+ | $ curl -I localhost | ||
+ | | ||
+ | HTTP/1.1 200 OK | ||
+ | Date: Tue, 05 Jul 2022 17:05:39 GMT | ||
+ | Server: Apache | ||
+ | Last-Modified: | ||
+ | ETag: " | ||
+ | Accept-Ranges: | ||
+ | Content-Length: | ||
+ | Vary: Accept-Encoding | ||
+ | Content-Type: | ||
+ | |||
+ | Mirem la informació que retorna ara amb una url d’una pàgina que no existeix: | ||
+ | |||
+ | {{:: | ||
+ | |||
+ | <WRAP todo> | ||
+ | Exercici: | ||
+ | |||
+ | Busca les diferents opcions per a la configuracio de ServerSignature i de ServerTokens. | ||
+ | </ | ||
+ | |||
+ | Solució: | ||
+ | ServerSignature – appears at the bottom of server generated pages such as error pages, | ||
+ | directory listings, etc. | ||
+ | It takes On/ | ||
+ | Admin’s email. | ||
+ | |||
+ | ServerTokens options - | ||
+ | | ||
+ | ServerTokens Full (or not specified) | ||
+ | Response to clients: Server: Apache/ | ||
+ | | ||
+ | ServerTokens Prod[uctOnly] | ||
+ | Response to clients: Server: Apache | ||
+ | | ||
+ | ServerTokens Major | ||
+ | Response to clients: Server: Apache/2 | ||
+ | | ||
+ | ServerTokens Minor | ||
+ | Response to clients: Server: Apache/2.4 | ||
+ | | ||
+ | ServerTokens Min[imal] | ||
+ | Response to clients: Server: Apache/ | ||
+ | | ||
+ | ServerTokens OS | ||
+ | Response to clients: Server: Apache/ | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== Limitacions tècniques del web scraping ===== | ||
+ | |||
+ | Per als operadors de les pàgines web sol ser **avantatjós limitar les possibilitats de scraping automàtic en el seu contingut en línia**. D'una banda, perquè l' | ||
+ | |||
+ | Per limitar l' | ||
+ | |||
+ | A continuació, | ||
+ | |||
+ | Comandes: | ||
+ | # Qualsevol bot | ||
+ | User-agent: * | ||
+ | # Excloure tot el directori principal | ||
+ | Disallow: / | ||
+ | |||
+ | |||
+ | El fitxer robots.txt només actua com a mesura de seguretat ja que convida a una limitació voluntària per part dels bots, que s' | ||
+ | |||
+ | ===== Les API com a alternativa al web scraping ===== | ||
+ | |||
+ | Tot i la seva efectivitat, | ||
+ | |||
+ | L'ús d'una API ofereix avantatges importants: | ||
+ | |||
+ | * **El propietari de la web crea l'API precisament per permetre accedir a les dades**. D' | ||
+ | * **L' | ||
+ | |||
+ | Sempre que hi hagi una API disponible i que ofereixi dades completes, aquest serà **el millor mètode per accedir a la informació**, | ||
+ | |||
+ | ===== Eines de scraping per a Python ===== | ||
+ | |||
+ | L' | ||
+ | * Scrapy | ||
+ | * Selenium | ||
+ | * BeautifulSoup | ||
+ | |||
+ | A continuació, | ||
+ | |||
+ | **Web scraping amb Scrapy** | ||
+ | |||
+ | Scrapy, una de les eines per fer web scraping amb Python que presentem, utilitza un analitzador sintàctic o **parser HTML** per extreure dades del text font (en HTML) de la web seguint aquest esquema: | ||
+ | |||
+ | URL → Solicitud HTTP → HTML → Scrapy | ||
+ | | ||
+ | El concepte clau del desenvolupament de scrapers amb Scrapy són els anomenats web spiders, programes de scraping senzills i basats en Scrapy. **Cada spider (aranya) està programat per scrapejar una web concreta** i es va despenjant de pàgina a pàgina. La programació utilitzada està orientada a objectes: cada spider és una classe de Python pròpia. | ||
+ | |||
+ | A més del paquet de Python en si, la instal·lació de Scrapy inclou una eina de línia d' | ||
+ | |||
+ | Scrapy és una plataforma consolidada per aplicar tècniques de web scraping amb Python. La seva arquitectura està **orientada a les necessitats de projectes professionals**. Scrapy compta, per exemple, amb una canonada o pipeline integrada per processar les dades extretes. L' | ||
+ | |||
+ | **Web scraping amb Selenium** | ||
+ | |||
+ | El programari lliure Selenium és un // | ||
+ | |||
+ | A diferència de Scrapy i BeautifulSoup, | ||
+ | |||
+ | URL → Sol·licitud HTTP → HTML → Selenium → DOM | ||
+ | |||
+ | Com que el DOM es genera de manera dinàmica, Selenium permet **scrapejar també pàgines el contingut de les quals ha estat generat mitjançant JavaScript**. L´accés a continguts dinàmics és l´avantatge més important de Selenium. En termes pràctics, Selenium també es pot fer servir en combinació amb Scrapy o amb BeautifulSoup: | ||
+ | |||
+ | URL → Sol·licitud HTTP → HTML → Selenium → DOM → HTML → Scrapy / BeautifulSoup | ||
+ | |||
+ | **Web scraping amb BeautifulSoup** | ||
+ | |||
+ | De les tres eines que presentem **per fer web scraping amb Python, BeautifulSoup és la més antiga**. Igual que en el cas de Scrapy, es tracta d'un parser o analitzador sintàctic HTML. El web scraping amb BeautifulSoup té la següent estructura: | ||
+ | |||
+ | URL → Sol·licitud HTTP → HTML → BeautifulSoup | ||
+ | |||
+ | Tot i això, a diferència de Scrapy, a BeautifulSoup el desenvolupament de l' | ||
+ | |||
+ | <WRAP center round important 100%> | ||
+ | ===== En resum ===== | ||
+ | **Quina eina hauries de triar pel teu projecte?** En resum: escull **BeautifulSoup** si necessites un desenvolupament ràpid o si vols familiaritzar-te primer amb els conceptes de Python i de web scraping. **Scrapy**, per la seva banda, et permet realitzar complexes aplicacions de web scraping a Python si disposes dels coneixements necessaris. **Selenium** serà la teva millor opció si la teva prioritat és extreure continguts dinàmics amb Python. | ||
+ | </ | ||