Eu, pessoalmente, prefiro usar scrapy e selênio e dockerizing em recipientes separados. Dessa forma, você pode instalar os sites com menos problemas e rastrear sites modernos que quase todos contêm javascript de uma forma ou de outra. Aqui está um exemplo:
Use o scrapy startproject
para criar seu raspador e escrever sua aranha, o esqueleto pode ser tão simples quanto isto:
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)
A verdadeira mágica acontece no middlewares.py. Substitua dois métodos no middleware do downloader __init__
e process_request
da seguinte maneira:
# 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)
Não se esqueça de ativar esse software intermediário, descomentando as próximas linhas no arquivo settings.py:
DOWNLOADER_MIDDLEWARES = {
'sample_project.middlewares.SampleProjectDownloaderMiddleware': 543,}
Avançar para dockerization. Crie a Dockerfile
partir de uma imagem leve (estou usando o python Alpine aqui), copie o diretório do projeto para ele, instale os requisitos:
# 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, finalmente, junte tudo 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
Corra docker-compose up -d
. Se você estiver fazendo isso pela primeira vez, levará um tempo para buscar o último selênio / cromo independente e criar a imagem do seu raspador também.
Uma vez feito, você pode verificar se seus contêineres estão em execução docker ps
e também se o nome do contêiner de selênio corresponde ao da variável de ambiente que passamos ao nosso contêiner de raspador (aqui estava SELENIUM_LOCATION=samplecrawler_selenium_1
).
Digite o contêiner do seu raspador com docker exec -ti YOUR_CONTAINER_NAME sh
, o comando para mim foi docker exec -ti samplecrawler_my_scraper_1 sh
: cd no diretório certo e execute o seu raspador scrapy crawl my_spider
.
A coisa toda está na minha página do github e você pode obtê-la aqui