Python Language
Web raspado con Python
Buscar..
Introducción
El raspado web es un proceso automatizado y programático a través del cual los datos se pueden " raspar " constantemente de las páginas web. También conocido como raspado de pantalla o recolección web, el raspado web puede proporcionar datos instantáneos desde cualquier página web de acceso público. En algunos sitios web, el raspado web puede ser ilegal.
Observaciones
Paquetes de Python útiles para raspado web (orden alfabético)
Realización de solicitudes y recogida de datos.
requests
Un paquete simple, pero poderoso para hacer peticiones HTTP.
requests-cache
Caché para requests
; almacenar datos en caché es muy útil. En desarrollo, significa que puede evitar golpear un sitio innecesariamente. Mientras ejecuta una colección real, significa que si su raspador se bloquea por algún motivo (tal vez no haya manejado algún contenido inusual en el sitio ... ¿Tal vez el sitio se haya caído ...?) Puede repetir la colección muy rápidamente de donde lo dejaste.
scrapy
Útil para crear rastreadores web, donde necesita algo más potente que usar requests
e iterar a través de páginas.
selenium
Enlaces Python para Selenium WebDriver, para la automatización del navegador. El uso de requests
para realizar solicitudes HTTP directamente es a menudo más sencillo para recuperar páginas web. Sin embargo, esto sigue siendo una herramienta útil cuando no es posible replicar el comportamiento deseado de un sitio usando solo las requests
, particularmente cuando se requiere JavaScript para representar elementos en una página.
Análisis de HTML
BeautifulSoup
Consulte documentos HTML y XML, utilizando varios analizadores diferentes (el analizador HTML incorporado de Python, html5lib
, lxml
o lxml.html
)
lxml
Procesos HTML y XML. Puede usarse para consultar y seleccionar contenido de documentos HTML a través de selectores de CSS y XPath.
Ejemplo básico de uso de solicitudes y lxml para raspar algunos datos
# 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()
Mantenimiento de sesión web-scraping con peticiones.
Es una buena idea mantener una sesión de raspado web para conservar las cookies y otros parámetros. Además, puede dar lugar a una mejora del rendimiento porque requests.Session
reutiliza la conexión TCP subyacente 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)
Raspado utilizando el marco de Scrapy
Primero tienes que configurar un nuevo proyecto Scrapy. Ingrese un directorio donde le gustaría almacenar su código y ejecute:
scrapy startproject projectName
Para raspar necesitamos una araña. Las arañas definen cómo se raspará un determinado sitio. Aquí está el código para una araña que sigue los enlaces a las preguntas más votadas en StackOverflow y raspa algunos datos de cada página ( fuente ):
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,
}
Guarda tus clases de arañas en el directorio nombre de projectName\spiders
. En este caso, projectName\spiders\stackoverflow_spider.py
.
Ahora puedes usar tu araña. Por ejemplo, intente ejecutar (en el directorio del proyecto):
scrapy crawl stackoverflow
Modificar agente de usuario de Scrapy
En ocasiones, el host bloquea el agente de usuario de Scrapy predeterminado ( "Scrapy/VERSION (+http://scrapy.org)"
). Para cambiar el agente de usuario predeterminado, abra settings.py , elimine el comentario y edite la siguiente línea como desee.
#USER_AGENT = 'projectName (+http://www.yourdomain.com)'
Por ejemplo
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'
Raspado utilizando 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
Raspado utilizando Selenium WebDriver
Algunos sitios web no les gusta ser raspado. En estos casos, es posible que necesite simular a un usuario real que trabaja con un navegador. Selenium lanza y controla un navegador 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)
El selenio puede hacer mucho más. Puede modificar las cookies del navegador, rellenar formularios, simular clics del ratón, tomar capturas de pantalla de páginas web y ejecutar JavaScript personalizado.
Descarga de contenido web simple con urllib.request
El módulo de biblioteca estándar urllib.request
se puede usar para descargar contenido 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 módulo similar también está disponible en Python 2 .
Raspado con rizo
importaciones:
from subprocess import Popen, PIPE
from lxml import etree
from io import StringIO
Descargando:
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
: descarga silenciosa
-A
: bandera de agente de usuario
Análisis:
tree = etree.parse(StringIO(result), etree.HTMLParser())
divs = tree.xpath('//div')