Personalmente preferisco usare scrapy e selenio e dockerizzare entrambi in contenitori separati. In questo modo è possibile installare sia con una seccatura minima sia eseguire la scansione di siti Web moderni che contengono quasi tutti javascript in un modo o nell'altro. Ecco un esempio:
Usa il scrapy startproject
per creare il tuo raschietto e scrivere il tuo ragno, lo scheletro può essere semplice come questo:
import scrapy
class MySpider(scrapy.Spider):
name = 'my_spider'
start_urls = ['https://somewhere.com']
def start_requests(self):
yield scrapy.Request(url=self.start_urls[0])
def parse(self, response):
# do stuff with results, scrape items etc.
# now were just checking everything worked
print(response.body)
La vera magia accade in middlewares.py. Sovrascrivi due metodi nel middleware downloader __init__
e process_request
, nel modo seguente:
# import some additional modules that we need
import os
from copy import deepcopy
from time import sleep
from scrapy import signals
from scrapy.http import HtmlResponse
from selenium import webdriver
class SampleProjectDownloaderMiddleware(object):
def __init__(self):
SELENIUM_LOCATION = os.environ.get('SELENIUM_LOCATION', 'NOT_HERE')
SELENIUM_URL = f'http://{SELENIUM_LOCATION}:4444/wd/hub'
chrome_options = webdriver.ChromeOptions()
# chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
self.driver = webdriver.Remote(command_executor=SELENIUM_URL,
desired_capabilities=chrome_options.to_capabilities())
def process_request(self, request, spider):
self.driver.get(request.url)
# sleep a bit so the page has time to load
# or monitor items on page to continue as soon as page ready
sleep(4)
# if you need to manipulate the page content like clicking and scrolling, you do it here
# self.driver.find_element_by_css_selector('.my-class').click()
# you only need the now properly and completely rendered html from your page to get results
body = deepcopy(self.driver.page_source)
# copy the current url in case of redirects
url = deepcopy(self.driver.current_url)
return HtmlResponse(url, body=body, encoding='utf-8', request=request)
Non dimenticare di abilitare questo middlware decommentando le righe successive nel file settings.py:
DOWNLOADER_MIDDLEWARES = {
'sample_project.middlewares.SampleProjectDownloaderMiddleware': 543,}
Avanti per la dockerizzazione. Crea il tuo Dockerfile
da un'immagine leggera (sto usando python Alpine qui), copia la directory del progetto su di essa, installa i requisiti:
# Use an official Python runtime as a parent image
FROM python:3.6-alpine
# install some packages necessary to scrapy and then curl because it's handy for debugging
RUN apk --update add linux-headers libffi-dev openssl-dev build-base libxslt-dev libxml2-dev curl python-dev
WORKDIR /my_scraper
ADD requirements.txt /my_scraper/
RUN pip install -r requirements.txt
ADD . /scrapers
E infine riunisci tutto in docker-compose.yaml
:
version: '2'
services:
selenium:
image: selenium/standalone-chrome
ports:
- "4444:4444"
shm_size: 1G
my_scraper:
build: .
depends_on:
- "selenium"
environment:
- SELENIUM_LOCATION=samplecrawler_selenium_1
volumes:
- .:/my_scraper
# use this command to keep the container running
command: tail -f /dev/null
Corri docker-compose up -d
. Se lo fai per la prima volta, ci vorrà un po 'prima che recuperi l'ultimo selenio / standalone-chrome e costruisca anche l'immagine del tuo raschietto.
Una volta fatto, puoi verificare che i tuoi contenitori siano in esecuzione docker ps
e anche che il nome del contenitore di selenio corrisponda a quello della variabile d'ambiente che abbiamo passato al nostro contenitore di raschietto (qui, eraSELENIUM_LOCATION=samplecrawler_selenium_1
).
Inserisci il tuo contenitore raschietto con docker exec -ti YOUR_CONTAINER_NAME sh
, il comando per me era docker exec -ti samplecrawler_my_scraper_1 sh
, cd nella directory giusta ed esegui il raschietto con scrapy crawl my_spider
.
L'intera cosa è sulla mia pagina github e puoi ottenerla da qui