Personalmente prefiero usar scrapy y selenio y dockerizar ambos en contenedores separados. De esta forma, puede instalar ambos con una molestia mínima y rastrear sitios web modernos que casi todos contienen JavaScript de una forma u otra. Aquí hay un ejemplo:
Use el scrapy startproject
para crear su raspador y escribir su araña, el esqueleto puede ser tan simple como esto:
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 verdadera magia ocurre en middlewares.py. Sobrescriba dos métodos en el middleware del descargador __init__
y process_request
, de la siguiente manera:
# 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)
No olvide habilitar este middlware descomentando las siguientes líneas en el archivo settings.py:
DOWNLOADER_MIDDLEWARES = {
'sample_project.middlewares.SampleProjectDownloaderMiddleware': 543,}
Siguiente para la dockerización. Cree su imagen a Dockerfile
partir de una imagen ligera (estoy usando python Alpine aquí), copie el directorio de su proyecto, instale los 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
Y finalmente reúne todo en 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
Ejecutar docker-compose up -d
. Si está haciendo esto la primera vez, le llevará un tiempo obtener el último selenio / cromo independiente y también construir su imagen de rascador.
Una vez hecho esto, puede verificar que sus contenedores se estén ejecutando docker ps
y también verificar que el nombre del contenedor de selenio coincida con el de la variable de entorno que pasamos a nuestro contenedor de raspador (aquí estaba SELENIUM_LOCATION=samplecrawler_selenium_1
).
Ingrese su contenedor de raspador con docker exec -ti YOUR_CONTAINER_NAME sh
, el comando para mí fue docker exec -ti samplecrawler_my_scraper_1 sh
, cd en el directorio correcto y ejecute su raspador con scrapy crawl my_spider
.
Todo está en mi página de Github y puedes obtenerlo desde aquí.