Clase 42: Un primer vistazo al uso básico de Scrapy

A continuación, presentaré un proyecto simple para completar el proceso de rastreo de Scrapy. A través de este proceso, podemos tener una comprensión general del uso y los principios básicos de Scrapy.

Objetivos de esta sección

Las tareas a realizar en esta sección son las siguientes.

  • Crea un proyecto Scrapy.
  • Cree una araña para rastrear el sitio y procesar los datos.
  • Exporta el contenido capturado a través de la línea de comando.
  • Guarde el contenido rastreado en la base de datos MongoDB.

El sitio de destino rastreado en esta sección es http://quotes.toscrape.com/.

Listo para trabajar

Necesitamos instalar el marco Scrapy, MongoDB y la biblioteca PyMongo. Si no se ha instalado, consulte las instrucciones de instalación en las secciones anteriores.

Crear proyecto

Cree un proyecto Scrapy, el archivo del proyecto se puede generar directamente con el comando scrapy, el comando es el siguiente:

scrapy startproject tutorial

Este comando se puede ejecutar en cualquier carpeta. Si se le solicita problemas de permisos, puede agregar sudo para ejecutar el comando. Este comando creará una carpeta llamada tutorial , la estructura de la carpeta es la siguiente:

scrapy.cfg     # Scrapy 部署时的配置文件
tutorial         # 项目的模块,引入的时候需要从这里引入
    __init__.py    
    items.py     # Items 的定义,定义爬取的数据结构
    middlewares.py   # Middlewares 的定义,定义爬取时的中间件
    pipelines.py       # Pipelines 的定义,定义数据管道
    settings.py       # 配置文件
    spiders         # 放置 Spiders 的文件夹
    __init__.py

Crear araña

Spider es una clase autodefinida. Scrapy la usa para tomar contenido de páginas web y analizar los resultados. Sin embargo, esta clase debe heredar la clase Spider scrapy.Spider proporcionada por Scrapy, y también definir el nombre y la solicitud inicial del Spider, así como cómo procesar los resultados del rastreo.

También puede crear una araña usando la línea de comando. Por ejemplo, para generar Quotes Spider, puede ejecutar el siguiente comando:

cd tutorial
scrapy genspider quotes     

Vaya a la carpeta del tutorial que acaba de crear y ejecute el comando genspider. El primer parámetro es el nombre de Spider y el segundo parámetro es el nombre de dominio del sitio web. Una vez completada la ejecución, hay un quote.py adicional en la carpeta spiders, que es el Spider que se acaba de crear, y el contenido es el siguiente:

import scrapy
​
class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ['http://quotes.toscrape.com/']
​
    def parse(self, response):
        pass

Hay tres atributos: nombre, dominios_permitidos y URL_inicio, y un método de análisis.

  • name: es el nombre único de cada elemento, que se utiliza para distinguir diferentes arañas.
  • dominios_permitidos: Es el nombre de dominio que se permite rastrear. Si el enlace de solicitud inicial o posterior no está bajo este nombre de dominio, el enlace de solicitud se filtrará.
  • start_urls: contiene la lista de URL rastreadas por Spider cuando se inicia, y la solicitud inicial la define.
  • parse: Es un método de Spider. De forma predeterminada, cuando se llama a la solicitud formada por los enlaces en start_urls, la respuesta se pasará a esta función como único parámetro después de que se complete la descarga. Este método es responsable de analizar la respuesta devuelta, extraer datos o generar más la solicitud para ser procesada.

Crear artículo

El elemento es un contenedor para almacenar datos rastreados y su uso es similar a un diccionario. Sin embargo, en comparación con el diccionario, Item tiene un mecanismo de protección adicional para evitar errores ortográficos o campos definidos incorrectamente.

Para crear un artículo, debe heredar la clase scrapy.Item y definir un campo de tipo scrapy.Field. Al observar el sitio web de destino, el contenido que podemos obtener es texto, autor, etiquetas.

Defina el elemento y modifique items.py de la siguiente manera:

import scrapy
​
class QuoteItem(scrapy.Item):
​
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

Aquí se definen tres campos y el nombre de la clase se cambia a QuoteItem. Usaremos este elemento en el siguiente rastreo.

Analizar respuesta

Como vimos anteriormente, la respuesta del parámetro del método de análisis es el resultado de rastrear los enlaces en start_urls. Entonces, en el método de análisis, podemos analizar directamente el contenido contenido en la variable de respuesta, como navegar por el código fuente de la página web del resultado de la solicitud, o analizar más el contenido del código fuente o encontrar el enlace en el resultado para obtener la siguiente solicitud.

Podemos ver que están los resultados que queremos y el enlace a la página siguiente en la página web Tenemos que lidiar con estas dos partes.

Primero observe la estructura de la página web, como se muestra en la figura. Cada página tiene varios bloques cuya clase es cita, y cada bloque contiene texto, autor y etiquetas. Luego, primero averiguamos todas las citas y luego extraemos el contenido de cada cita.
Inserte la descripción de la imagen aquí
El método de extracción puede ser un selector de CSS o un selector de XPath. Aquí usamos selectores CSS para la selección, y la reescritura del método de análisis es la siguiente:

def parse(self, response):
    quotes = response.css('.quote')
    for quote in quotes:
        text = quote.css('.text::text').extract_first()
        author = quote.css('.author::text').extract_first()
        tags = quote.css('.tags .tag::text').extract()

Aquí primero usamos el selector para seleccionar todas las citas y asignarlas a la variable de cotización, y luego usamos el bucle for para recorrer cada cita y analizar el contenido de cada cita.

Para el texto, se observa que su clase es texto, por lo que puede usar el selector .text para seleccionar. El resultado es en realidad el nodo etiquetado completo. Para obtener su contenido de texto, puede agregar :: text para obtenerlo. En este momento, el resultado es una lista de longitud 1, por lo que debe utilizar el método extract_first para obtener el primer elemento. Para las etiquetas, como queremos obtener todas las etiquetas, podemos usar el método de extracción para obtener la lista completa.

Tome el resultado de la primera cita como ejemplo, la descripción de cada método de selección y resultado es la siguiente.

El código fuente es el siguiente:

<div class="quote" itemscope=""itemtype="http://schema.org/CreativeWork">
        <span class="text" itemprop="text">“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”</span>
        <span>by <small class="author" itemprop="author">Albert Einstein</small>
        <a href="/author/Albert-Einstein">(about)</a>
        </span>
        <div class="tags">
            Tags:
            <meta class="keywords" itemprop="keywords" content="change,deep-thoughts,thinking,world"> 
            <a class="tag" href="/tag/change/page/1/">change</a>
            <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
            <a class="tag" href="/tag/thinking/page/1/">thinking</a>
            <a class="tag" href="/tag/world/page/1/">world</a>
        </div>
    </div>

Los resultados devueltos de diferentes selectores son los siguientes.

quote.css ('. texto')

[<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' text ')]"data='<span class="text"itemprop="text">“The '>]

quote.css ('. texto :: texto')

[<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' text ')]/text()"data='“The world as we have created it is a pr'>]

quote.css ('. texto'). extract ()

['<span class="text"itemprop="text">“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”</span>']

quote.css ('. texto :: texto'). extract ()

['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”']

quote.css ('. texto :: texto'). extract_first ()

“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.

Utilizar artículo

El artículo se define arriba y luego lo usaremos. El elemento puede entenderse como un diccionario, pero debe crearse una instancia cuando se declara. Luego asigne cada campo del artículo con el resultado del análisis en este momento y, finalmente, devuelva el artículo.

QuotesSpider 的改写如下所示:
import scrapy
from tutorial.items import QuoteItem
​
class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ['http://quotes.toscrape.com/']
​
    def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

De esta manera, todo el contenido de la página de inicio se analiza y se asigna a QuoteItem.

Solicitud de seguimiento

La operación anterior se da cuenta de la captura de contenido de la página inicial. Entonces, ¿cómo se debe rastrear el contenido de la página siguiente? Esto requiere que busquemos información de la página actual para generar la siguiente solicitud, y luego busquemos la información en la siguiente página solicitada para construir la siguiente solicitud. De esta manera, itera hacia adelante y hacia atrás para lograr el rastreo de todo el sitio.

Tire de la página justo ahora hacia la parte inferior, como se muestra en la figura.
Inserte la descripción de la imagen aquí
Hay un botón Siguiente, verifique el código fuente, puede encontrar que su enlace es / page / 2 /, de hecho, el enlace completo es: http://quotes.toscrape.com/page/2, a través de este enlace podemos construir el siguiente una solicitud.

Scrapy.Request es necesario al construir la solicitud. Aquí pasamos dos parámetros: url y callback La descripción de estos dos parámetros es la siguiente.

  • url: es un enlace de solicitud.
  • devolución de llamada: es una función de devolución de llamada. Cuando se completa la solicitud que especifica la función de devolución de llamada, se obtiene la respuesta y el motor pasará la respuesta como parámetro a la función de devolución de llamada. La función de devolución de llamada analiza o genera la siguiente solicitud. La función de devolución de llamada se muestra en parse () arriba.

Dado que el análisis es la forma de analizar el texto, el autor y las etiquetas, y la estructura de la página siguiente es la misma que la estructura de la página que se acaba de analizar, podemos utilizar el método de análisis de nuevo para realizar el análisis de la página.

Lo siguiente que tenemos que hacer es usar el selector para obtener el enlace de la página siguiente y generar la solicitud, y agregar el siguiente código después del método de análisis:

next = response.css('.pager .next a::attr(href)').extract_first()
url = response.urljoin(next)
yield scrapy.Request(url=url, callback=self.parse)

La primera frase de código primero obtiene el enlace de la página siguiente a través del selector CSS, es decir, para obtener el atributo href en un hipervínculo. Aquí se utiliza la operación :: attr (href). Luego llame al método extract_first para obtener el contenido.

El segundo código llama al método urljoin . El método urljoin () puede construir una URL relativa en una URL absoluta. Por ejemplo, la siguiente dirección de página obtenida es / page / 2, y el resultado obtenido después de que se procesa el método urljoin es: http://quotes.toscrape.com/page/2/ .

La tercera oración de código construye una nueva solicitud a través de URL y variables de devolución de llamada, y la devolución de llamada de la función de devolución de llamada aún usa el método de análisis. Una vez que se completa la solicitud, la respuesta se procesará a través del método de análisis nuevamente para obtener el resultado del análisis de la segunda página y luego generar la siguiente página de la segunda página, que es la solicitud de la tercera página. De esta forma, el rastreador entra en un bucle hasta la última página.

Con unas pocas líneas de código, podemos implementar fácilmente un bucle de rastreo para capturar los resultados de cada página. Ahora, toda la clase Spider después de reescribir es la siguiente:

import scrapy
from tutorial.items import QuoteItem
​
class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ['http://quotes.toscrape.com/']
​
    def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item
​
        next = response.css('.pager .next a::attr("href")').extract_first()
        url = response.urljoin(next)
        yield scrapy.Request(url=url, callback=self.parse)

correr

A continuación, ingrese al directorio y ejecute el siguiente comando:

scrapy crawl quotes

Puedes ver los resultados de Scrapy.

2020-02-19 13:37:20 [scrapy.utils.log] INFO: Scrapy 1.3.0 started (bot: tutorial)
2020-02-19 13:37:20 [scrapy.utils.log] INFO: Overridden settings: {
    
    'NEWSPIDER_MODULE': 'tutorial.spiders', 'SPIDER_MODULES': ['tutorial.spiders'], 'ROBOTSTXT_OBEY': True, 'BOT_NAME': 'tutorial'}
2020-02-19 13:37:20 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2020-02-19 13:37:20 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',

Estos son solo parte de los resultados de ejecución, algunos de los resultados de captura se han omitido.
Primero, Scrapy genera el número de versión actual y el nombre del proyecto que se está iniciando. Luego genere algunas configuraciones reescritas en el settings.py actual. Luego genere los Middlewares y Pipelines actualmente aplicados. Middlewares está habilitado de forma predeterminada y se puede modificar en settings.py. Pipelines está vacío de forma predeterminada y también se puede configurar en settings.py. Se explicarán más adelante.

El siguiente paso es generar los resultados del rastreo de cada página. Puede ver que el rastreador analiza y pasa la página hasta que se rastrea todo el contenido y, luego, finaliza.

Finalmente, Scrapy genera información estadística de todo el proceso de rastreo, como el número de bytes solicitados, el número de solicitudes, el número de respuestas y el motivo de la finalización.

Todo el programa Scrapy se ejecuta correctamente. Hemos completado el rastreo del contenido de un sitio web con un código muy simple, que es mucho más simple que escribir un pequeño programa antes.

Guardar en archivo

Después de ejecutar Scrapy, solo vimos la salida en la consola. ¿Qué pasa si quiero guardar los resultados?

Para completar esta tarea, no se requiere ningún código adicional. Las exportaciones de feeds proporcionadas por Scrapy pueden generar fácilmente los resultados del rastreo. Por ejemplo, si queremos guardar el resultado anterior como un archivo JSON, podemos ejecutar el siguiente comando:

scrapy crawl quotes -o quotes.json

Después de que se ejecuta el comando, hay un archivo quotes.json adicional en el proyecto. El archivo contiene todo el contenido recién capturado y el contenido está en formato JSON.

Además, también podemos generar una línea de JSON para cada elemento, el sufijo de salida es jl, que es la abreviatura de jsonline, el comando es el siguiente:

scrapy crawl quotes -o quotes.jl

o

scrapy crawl quotes -o quotes.jsonlines

También se admiten muchos formatos de salida, como csv, xml, pickle, marshal, etc., y la salida remota como ftp, s3, etc., y se pueden lograr otras salidas personalizando ItemExporter.

Por ejemplo, la salida correspondiente a los siguientes comandos son csv, xml, pickle, formato marshal y salida remota ftp:

scrapy crawl quotes -o quotes.csv
scrapy crawl quotes -o quotes.xml
scrapy crawl quotes -o quotes.pickle
scrapy crawl quotes -o quotes.marshal
scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv

Entre ellos, la salida ftp necesita configurar correctamente el nombre de usuario, la contraseña, la dirección y la ruta de salida; de lo contrario, se informará un error.

A través de las exportaciones de feeds proporcionadas por Scrapy, podemos exportar fácilmente los resultados del rastreo a un archivo. Para algunos proyectos pequeños, esto debería ser suficiente. Pero si desea una salida más compleja, como la salida a una base de datos, podemos usar Item Pileline para completar.

Usar canalización de artículos

Si desea realizar operaciones más complejas, como guardar los resultados en la base de datos MongoDB, o filtrar algunos elementos útiles, podemos definir Item Pipeline para lograrlo.

Item Pipeline es el pipeline del proyecto. Cuando se genera el artículo, se enviará automáticamente a la canalización de artículos para su procesamiento. A menudo usamos la canalización de artículos para realizar las siguientes operaciones.

  • Limpiar datos HTML;
  • Verifique los datos rastreados y verifique los campos rastreados;
  • Verifique el contenido duplicado y descarte el contenido duplicado;
  • Almacene los resultados del rastreo en la base de datos.

Implementar Item Pipeline es muy simple, simplemente defina una clase e implemente el método process_item . Después de habilitar Item Pipeline, Item Pipeline llamará automáticamente a este método. El método process_item debe devolver un diccionario o un objeto Item que contenga los datos, o lanzar una excepción DropItem.

El método process_item tiene dos parámetros. Un parámetro es el elemento , y cada elemento generado por Spider se pasará como parámetro. El otro parámetro es spider , que es una instancia de Spider.

A continuación, implementamos una canalización de elementos para filtrar los elementos cuya longitud de texto sea superior a 50 y guardar los resultados en MongoDB.

Modifique el archivo pipelines.py en el proyecto. El contenido del archivo generado automáticamente por la línea de comando se puede eliminar y se agrega una clase TextPipeline. El contenido es el siguiente:

from scrapy.exceptions import DropItem
​
class TextPipeline(object):
    def __init__(self):
        self.limit = 50
    
    def process_item(self, item, spider):
        if item['text']:
            if len(item['text']) > self.limit:
                item['text'] = item['text'][0:self.limit].rstrip() + '...'
            return item
        else:
            return DropItem('Missing Text')

Este código define una longitud límite de 50 en el método de construcción e implementa el método process_item, cuyos parámetros son item y spider. Primero, este método juzga si el atributo de texto del elemento existe, y si no existe, lanza una excepción DropItem; si existe, juzga si la longitud es mayor que 50, y si es mayor, luego trunca y empalma la elipsis, y luego devuelve el elemento.

A continuación, guardamos el elemento procesado en MongoDB y definimos otro Pipeline. También en pipelines.py, implementamos otra clase MongoPipeline, el contenido es el siguiente:

import pymongo
​
class MongoPipeline(object):
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db
​
    @classmethod
    def from_crawler(cls, crawler):
        return cls(mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DB')
        )
​
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
​
    def process_item(self, item, spider):
        name = item.__class__.__name__
        self.db[name].insert(dict(item))
        return item
​
    def close_spider(self, spider):
        self.client.close()

La clase MongoPipeline implementa varios otros métodos definidos por la API.

  • from_crawler: Este es un método de clase, identificado por @classmethod, que es una forma de inyección de dependencias. El parámetro del método es crawler. A través del parámetro crawler, podemos obtener cada información de configuración de la configuración global, en la configuración global settings.py Podemos definir MONGO_URI y MONGO_DB para especificar la dirección y el nombre de la base de datos requeridos para la conexión MongoDB, y devolver el objeto de clase después de obtener la información de configuración. Entonces, la definición de este método se usa principalmente para obtener la configuración en settings.py.

  • open_spider: este método se llama cuando se abre Spider. Algunas operaciones de inicialización se llevan a cabo principalmente aquí.

  • close_spider: cuando se cierra Spider, se llamará a este método para cerrar la conexión de la base de datos aquí.

El método principal process_item realiza la operación de inserción de datos.

Después de definir las dos clases TextPipeline y MongoPipeline, debemos usarlas en settings.py. Es necesario definir la información de conexión de MongoDB.

Agregamos el siguiente contenido a settings.py:

ITEM_PIPELINES = {
    
    
   'tutorial.pipelines.TextPipeline': 300,
   'tutorial.pipelines.MongoPipeline': 400,
}
MONGO_URI='localhost'
MONGO_DB='tutorial'

Asigne el diccionario ITEM_PIPELINES, el nombre clave es el nombre de la clase Pipeline y el valor clave es la prioridad de llamada, que es un número. Cuanto menor sea el número, antes se llamará al Pipeline correspondiente.

Vuelva a ejecutar el rastreo de nuevo, el comando es el siguiente:

scrapy crawl quotes

Después del rastreo, se crean una base de datos de tutorial y una tabla QuoteItem en MongoDB, como se muestra en la figura.
Inserte la descripción de la imagen aquí

Código

La dirección de código de esta sección: https://github.com/Python3WebSpider/ScrapyTutorial .

Conclusión

Hemos completado una introducción simple a Scrapy rastreando el sitio web de Cotizaciones. Pero esto es solo la punta del iceberg, y todavía hay mucho contenido esperando que lo exploremos.

Supongo que te gusta

Origin blog.csdn.net/weixin_38819889/article/details/107935647
Recomendado
Clasificación