Python Language
Webschrapen met Python
Zoeken…
Invoering
Webschrapen is een geautomatiseerd, programmatisch proces waardoor gegevens constant van webpagina's kunnen worden 'geschraapt'. Web scraping, ook bekend als screen scraping of web harvesting, kan direct gegevens opleveren van elke openbaar toegankelijke webpagina. Op sommige websites kan webschrapen illegaal zijn.
Opmerkingen
Handige Python-pakketten voor webscraping (alfabetische volgorde)
Verzoeken doen en gegevens verzamelen
requests
Een eenvoudig, maar krachtig pakket voor het doen van HTTP-verzoeken.
requests-cache
Caching voor requests
; cachegegevens zijn erg handig. In ontwikkeling betekent dit dat u kunt voorkomen dat u onnodig een site bezoekt. Terwijl je een echte collectie beheert, betekent dit dat als je krabber om de een of andere reden crasht (misschien heb je geen ongewone inhoud op de site behandeld ...? Misschien is de site offline gegaan??), Je de collectie heel snel kunt herhalen van waar je was gebleven.
scrapy
Handig voor het bouwen van webcrawlers, waarbij u iets nodig hebt dat krachtiger is dan het gebruik van requests
en het doorlopen van pagina's.
selenium
Python-bindingen voor Selenium WebDriver, voor browserautomatisering. Het gebruik van requests
om HTTP-aanvragen rechtstreeks te doen, is vaak eenvoudiger voor het ophalen van webpagina's. Dit blijft echter een handig hulpmiddel wanneer het niet mogelijk is om het gewenste gedrag van een site te repliceren met alleen requests
, vooral wanneer JavaScript vereist is om elementen op een pagina weer te geven.
HTML parsing
BeautifulSoup
Vraag HTML- en XML-documenten op, met behulp van een aantal verschillende parsers (Python's ingebouwde HTML Parser, html5lib
, lxml
of lxml.html
)
lxml
Verwerkt HTML en XML. Kan worden gebruikt voor het opvragen en selecteren van inhoud uit HTML-documenten via CSS-selectors en XPath.
Eenvoudig voorbeeld van het gebruik van verzoeken en lxml om sommige gegevens te schrapen
# 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()
Web-scraping-sessie met verzoeken onderhouden
Het is een goed idee om een webschrapsessie te houden om de cookies en andere parameters te behouden. Bovendien kan het leiden tot een prestatieverbetering omdat requests.Session
de onderliggende TCP-verbinding met een host opnieuw gebruikt:
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)
Schrapen met behulp van het Scrapy-framework
Eerst moet je een nieuw Scrapy-project opzetten. Voer een map in waar u uw code wilt opslaan en voer uit:
scrapy startproject projectName
Om te schrapen hebben we een spin nodig. Spinnen bepalen hoe een bepaalde site wordt geschraapt. Hier is de code voor een spin die de links volgt naar de meest gestemde vragen over StackOverflow en wat gegevens van elke pagina ( bron ) verwijdert:
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,
}
Sla uw spider-klassen op in de map projectName\spiders
. In dit geval - projectName\spiders\stackoverflow_spider.py
.
Nu kunt u uw spin gebruiken. Probeer bijvoorbeeld uit te voeren (in de map van het project):
scrapy crawl stackoverflow
Wijzig Scrapy user agent
Soms wordt de standaard Scrapy-gebruikersagent ( "Scrapy/VERSION (+http://scrapy.org)"
) geblokkeerd door de host. Als u de standaard user-agent wilt wijzigen, opent u settings.py , uncomment en bewerkt u de volgende regel naar wens.
#USER_AGENT = 'projectName (+http://www.yourdomain.com)'
Bijvoorbeeld
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'
Schrapen met 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
Schrapen met Selenium WebDriver
Sommige websites houden er niet van om geschraapt te worden. In deze gevallen moet u mogelijk een echte gebruiker simuleren die met een browser werkt. Selenium lanceert en bestuurt een webbrowser.
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)
Selenium kan veel meer. Het kan de cookies van de browser wijzigen, formulieren invullen, muisklikken simuleren, screenshots van webpagina's maken en aangepaste JavaScript uitvoeren.
Eenvoudig downloaden van webcontent met urllib.request
De standaard bibliotheekmodule urllib.request
kan worden gebruikt om webinhoud te downloaden:
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)
Een vergelijkbare module is ook beschikbaar in Python 2 .
Schrapen met krullen
invoer:
from subprocess import Popen, PIPE
from lxml import etree
from io import StringIO
downloaden:
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
: stille download
-A
: user agent vlag
parseren:
tree = etree.parse(StringIO(result), etree.HTMLParser())
divs = tree.xpath('//div')