Python Language
Raspare Web con Python
Ricerca…
introduzione
Lo scraping Web è un processo programmatico automatizzato attraverso il quale i dati possono essere costantemente "raschiati" fuori dalle pagine Web. Conosciuto anche come screen scraping o web harvesting, il web scraping può fornire dati istantanei da qualsiasi pagina web accessibile al pubblico. Su alcuni siti Web, il web scraping potrebbe essere illegale.
Osservazioni
Utili pacchetti Python per lo scraping web (in ordine alfabetico)
Fare richieste e raccogliere dati
requests
Un semplice ma potente pacchetto per fare richieste HTTP.
requests-cache
Memorizzazione nella cache delle requests
; i dati di memorizzazione nella cache sono molto utili. In fase di sviluppo, significa che puoi evitare di colpire un sito inutilmente. Quando si esegue una vera raccolta, significa che se il tuo raschietto si blocca per qualche motivo (forse non hai gestito alcuni contenuti insoliti sul sito ...? Forse il sito è andato giù ...?) Puoi ripetere la raccolta molto velocemente da dove eri rimasto.
scrapy
Utile per creare web crawler, dove è necessario qualcosa di più potente dell'uso di requests
e iterazione attraverso le pagine.
selenium
Collegamenti Python per Selenium WebDriver, per l'automazione del browser. L'utilizzo delle requests
per effettuare direttamente richieste HTTP è spesso più semplice per il recupero di pagine Web. Tuttavia, questo rimane uno strumento utile quando non è possibile replicare il comportamento desiderato di un sito utilizzando solo le requests
, in particolare quando è richiesto JavaScript per il rendering di elementi in una pagina.
Analisi HTML
BeautifulSoup
Interrogare i documenti HTML e XML, utilizzando un numero di parser diversi (Parser HTML incorporato di Python, html5lib
, lxml
o lxml.html
)
lxml
Elabora HTML e XML. Può essere usato per interrogare e selezionare il contenuto da documenti HTML tramite selettori CSS e XPath.
Esempio di base di utilizzo di richieste e lxml per raschiare alcuni dati
# For Python 2 compatibility.
from __future__ import print_function
import lxml.html
import requests
def main():
r = requests.get("https://httpbin.org")
html_source = r.text
root_element = lxml.html.fromstring(html_source)
# Note root_element.xpath() gives a *list* of results.
# XPath specifies a path to the element we want.
page_title = root_element.xpath('/html/head/title/text()')[0]
print(page_title)
if __name__ == '__main__':
main()
Mantenimento della sessione di web scraping con le richieste
È consigliabile mantenere una sessione di web-scraping per mantenere i cookie e altri parametri. Inoltre, può comportare un miglioramento delle prestazioni poiché requests.Session
riutilizza la connessione TCP sottostante a un host:
import requests
with requests.Session() as session:
# all requests through session now have User-Agent header set
session.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'}
# set cookies
session.get('http://httpbin.org/cookies/set?key=value')
# get cookies
response = session.get('http://httpbin.org/cookies')
print(response.text)
Raschiare usando il framework Scrapy
Per prima cosa devi creare un nuovo progetto Scrapy. Inserisci una directory in cui desideri memorizzare il codice ed esegui:
scrapy startproject projectName
Per raschiare abbiamo bisogno di un ragno. Gli spider definiscono come verrà raschiato un determinato sito. Ecco il codice per uno spider che segue i link alle domande più votate su StackOverflow e cancella alcuni dati da ciascuna pagina ( fonte ):
import scrapy
class StackOverflowSpider(scrapy.Spider):
name = 'stackoverflow' # each spider has a unique name
start_urls = ['http://stackoverflow.com/questions?sort=votes'] # the parsing starts from a specific set of urls
def parse(self, response): # for each request this generator yields, its response is sent to parse_question
for href in response.css('.question-summary h3 a::attr(href)'): # do some scraping stuff using css selectors to find question urls
full_url = response.urljoin(href.extract())
yield scrapy.Request(full_url, callback=self.parse_question)
def parse_question(self, response):
yield {
'title': response.css('h1 a::text').extract_first(),
'votes': response.css('.question .vote-count-post::text').extract_first(),
'body': response.css('.question .post-text').extract_first(),
'tags': response.css('.question .post-tag::text').extract(),
'link': response.url,
}
Salva le tue classi spider nella directory projectName\spiders
. In questo caso - projectName\spiders\stackoverflow_spider.py
.
Ora puoi usare il tuo ragno. Ad esempio, prova a eseguire (nella directory del progetto):
scrapy crawl stackoverflow
Modifica agente utente Scrapy
A volte l'agente utente Scrapy predefinito ( "Scrapy/VERSION (+http://scrapy.org)"
) viene bloccato dall'host. Per cambiare l'agente utente predefinito, apri settings.py , decommenta e modifica la riga seguente per quello che vuoi.
#USER_AGENT = 'projectName (+http://www.yourdomain.com)'
Per esempio
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
Raschiare usando BeautifulSoup4
from bs4 import BeautifulSoup
import requests
# Use the requests module to obtain a page
res = requests.get('https://www.codechef.com/problems/easy')
# Create a BeautifulSoup object
page = BeautifulSoup(res.text, 'lxml') # the text field contains the source of the page
# Now use a CSS selector in order to get the table containing the list of problems
datatable_tags = page.select('table.dataTable') # The problems are in the <table> tag,
# with class "dataTable"
# We extract the first tag from the list, since that's what we desire
datatable = datatable_tags[0]
# Now since we want problem names, they are contained in <b> tags, which are
# directly nested under <a> tags
prob_tags = datatable.select('a > b')
prob_names = [tag.getText().strip() for tag in prob_tags]
print prob_names
Raschiatura usando Selenium WebDriver
Alcuni siti Web non amano essere raschiati. In questi casi potrebbe essere necessario simulare un utente reale che lavora con un browser. Selenium lancia e controlla un browser web.
from selenium import webdriver
browser = webdriver.Firefox() # launch firefox browser
browser.get('http://stackoverflow.com/questions?sort=votes') # load url
title = browser.find_element_by_css_selector('h1').text # page title (first h1 element)
questions = browser.find_elements_by_css_selector('.question-summary') # question list
for question in questions: # iterate over questions
question_title = question.find_element_by_css_selector('.summary h3 a').text
question_excerpt = question.find_element_by_css_selector('.summary .excerpt').text
question_vote = question.find_element_by_css_selector('.stats .vote .votes .vote-count-post').text
print "%s\n%s\n%s votes\n-----------\n" % (question_title, question_excerpt, question_vote)
Il selenio può fare molto di più. Può modificare i cookie del browser, compilare moduli, simulare clic del mouse, acquisire schermate di pagine Web ed eseguire JavaScript personalizzato.
Download semplice di contenuti Web con urllib.request
Il modulo di libreria standard urllib.request
può essere utilizzato per scaricare contenuti web:
from urllib.request import urlopen
response = urlopen('http://stackoverflow.com/questions?sort=votes')
data = response.read()
# The received bytes should usually be decoded according the response's character set
encoding = response.info().get_content_charset()
html = data.decode(encoding)
Un modulo simile è disponibile anche in Python 2 .
Raschiando con arricciatura
importazioni:
from subprocess import Popen, PIPE
from lxml import etree
from io import StringIO
Download:
user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'
url = 'http://stackoverflow.com'
get = Popen(['curl', '-s', '-A', user_agent, url], stdout=PIPE)
result = get.stdout.read().decode('utf8')
-s
: download silenzioso
-A
: flag agente utente
di analisi:
tree = etree.parse(StringIO(result), etree.HTMLParser())
divs = tree.xpath('//div')