Osobiście wolę używać złomu i selenu oraz dokeryzować oba w osobnych pojemnikach. W ten sposób możesz zainstalować zarówno przy minimalnym wysiłku, jak i przeszukiwać nowoczesne strony internetowe, które prawie wszystkie zawierają JavaScript w takiej czy innej formie. Oto przykład:
Użyj, scrapy startproject
aby stworzyć skrobak i napisać pająka, szkielet może być tak prosty:
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)
Prawdziwa magia dzieje się w middlewares.py. Zastąp dwie metody w oprogramowaniu pośredniczącym pobierania __init__
i process_request
w następujący sposób:
# 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)
Nie zapomnij włączyć tego oprogramowania pośredniego, odkomentowując kolejne wiersze w pliku settings.py:
DOWNLOADER_MIDDLEWARES = {
'sample_project.middlewares.SampleProjectDownloaderMiddleware': 543,}
Dalej do dokeryzacji. Utwórz swój Dockerfile
z lekkiego obrazu (używam tutaj Python Alpine), skopiuj do niego katalog projektu, zainstaluj wymagania:
# 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
I wreszcie zbierz to wszystko razem w 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
Biegać docker-compose up -d
. Jeśli robisz to za pierwszym razem, pobranie najnowszego selenu / samodzielnego chromu zajmie trochę czasu, a także zbudowanie obrazu skrobaka.
Po zakończeniu możesz sprawdzić, czy Twoje kontenery są uruchomione, docker ps
a także sprawdzić, czy nazwa kontenera selenu jest zgodna ze zmienną środowiskową, którą przekazaliśmy do naszego kontenera skrobaka (tutaj było toSELENIUM_LOCATION=samplecrawler_selenium_1
).
Wprowadź swój pojemnik na skrobaki za pomocą docker exec -ti YOUR_CONTAINER_NAME sh
, polecenie dla mnie brzmiało docker exec -ti samplecrawler_my_scraper_1 sh
, cd do odpowiedniego katalogu i uruchom skrobak za pomocą scrapy crawl my_spider
.
Całość jest na mojej stronie github i możesz ją pobrać stąd