Saltar al contenido

¿Cómo raspar todo el contenido de cada enlace con scrapy?

Nuestro team de trabajo ha estado largas horas investigando para dar soluciones a tus búsquedas, te regalamos la soluciones y esperamos serte de gran ayuda.

Solución:

Para crear un andamio en un proyecto scrapy básico, puede usar el comando:

scrapy startproject craig

Luego agregue la araña y los elementos:

craig / arañas / spider.py

from scrapy import Spider
from craig.items import CraigslistSampleItem
from scrapy.linkextractors.lxmlhtml import LxmlLinkExtractor
from scrapy.selector import Selector
from scrapy import Request
import urlparse, re

class CraigSpider(Spider):
    name = "craig"
    start_url = "https://sfbay.craigslist.org/search/npo"

    def start_requests(self):

        yield Request(self.start_url, callback=self.parse_results_page)


    def parse_results_page(self, response):

        sel = Selector(response)

        # Browse paging.
        page_urls = sel.xpath(""".//span[@class='buttons']/a[@class='button next']/@href""").getall()

        for page_url in page_urls + [response.url]:
            page_url = urlparse.urljoin(self.start_url, page_url)

            # Yield a request for the next page of the list, with callback to this same function: self.parse_results_page().
            yield Request(page_url, callback=self.parse_results_page)

        # Browse items.
        item_urls = sel.xpath(""".//*[@id='sortable-results']//li//a/@href""").getall()

        for item_url in item_urls:
            item_url = urlparse.urljoin(self.start_url, item_url)

            # Yield a request for each item page, with callback self.parse_item().
            yield Request(item_url, callback=self.parse_item)


    def parse_item(self, response):

        sel = Selector(response)

        item = CraigslistSampleItem()

        item['title'] = sel.xpath('//*[@id="titletextonly"]').extract_first()
        item['body'] = sel.xpath('//*[@id="postingbody"]').extract_first()
        item['link'] = response.url

        yield item

craig / items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items

from scrapy.item import Item, Field

class CraigslistSampleItem(Item):
    title = Field()
    body = Field()
    link = Field()

craig / settings.py

# -*- coding: utf-8 -*-

BOT_NAME = 'craig'

SPIDER_MODULES = ['craig.spiders']
NEWSPIDER_MODULE = 'craig.spiders'

ITEM_PIPELINES = 
   'craig.pipelines.CraigPipeline': 300,

craig / pipelines.py

from scrapy import signals
from scrapy.xlib.pydispatch import dispatcher
from scrapy.exporters import CsvItemExporter

class CraigPipeline(object):

    def __init__(self):
        dispatcher.connect(self.spider_opened, signals.spider_opened)
        dispatcher.connect(self.spider_closed, signals.spider_closed)
        self.files = 

    def spider_opened(self, spider):
        file = open('%s_ads.csv' % spider.name, 'w+b')
        self.files[spider] = file
        self.exporter = CsvItemExporter(file)
        self.exporter.start_exporting()

    def spider_closed(self, spider):
        self.exporter.finish_exporting()
        file = self.files.pop(spider)
        file.close()

    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

Puede ejecutar la araña ejecutando el comando:

scrapy runspider craig/spiders/spider.py

Desde la raíz de tu proyecto.

Debería crear un craig_ads.csv en la raíz de su proyecto.

Estoy tratando de responder a tu pregunta.

En primer lugar, por tu consulta XPath incorrecta, tienes resultados en blanco. Por XPath ".//*[@id='sortable-results']//ul//li//p", te encuentras relevante

nodos correctamente, aunque no me gusta su expresión de consulta. Sin embargo, no tengo idea de su siguiente expresión XPath ".//*[@id='titletextonly']" y "a/@href", no pudieron ubicar el enlace y el título como esperaba. Quizás su significado sea ubicar el texto del título y el hipervínculo del título. En caso afirmativo, creo que debe aprender Xpath y comenzar con HTML DOM.

Quiero instruirle sobre cómo realizar consultas XPath, ya que hay muchos recursos en línea. Me gustaría mencionar algunas características del selector Scrapy XPath:

  1. Scrapy XPath Selector es un contenedor mejorado de la consulta XPath estándar.

En la consulta XPath estándar, devuelve un array de los nodos DOM que consultaste. Puede abrir el modo de desarrollo de su navegador (F12), use el comando de la consola $x(x_exp) Probar. Le sugiero encarecidamente que pruebe su expresión XPath de esta manera. Le dará resultados instantáneos y le ahorrará mucho tiempo. Si tiene tiempo, familiarícese con las herramientas de desarrollo web de su navegador, que le permitirán comprender rápidamente la estructura de la página web y localizar la entrada que está buscando.

Mientras, Scrapy response.xpath(x_exp) devuelve un array de Selector objetos correspondientes a la consulta XPath real, que en realidad es una SelectorList objeto. Esto significa que los resultados de XPath están representados por SelectorsList. Y ambos Selector y SelectorList La clase proporciona algunas funciones útiles para operar los resultados:

  • extract, devuelve una lista de nodos de documentos serializados (a cadenas Unicode)
  • extract_first, return escalar, first de El extract resultados
  • re, devuelve una lista, re de El extract resultados
  • re_first, return escalar, first de El re resultados.

Estas funciones hacen que su programación sea mucho más conveniente. Un ejemplo es que puedes llamar xpath funcionar directamente en SelectorList objeto. Si lo intentaste lxml antes, verías que esto es muy útil: si quieres llamar xpath función en los resultados de un ex xpath resultados en lxml, tienes que iterar sobre los resultados anteriores. Otro ejemplo es que cuando definitivamente está seguro de que hay como máximo un elemento en esa lista, puede usar extract_first para obtener un valor escalar, en lugar de usar el método de índice de lista (por ejemplo, rlist[0]) que causaría una excepción fuera del índice cuando ningún elemento coincidiera. Recuerde que siempre hay excepciones cuando analiza la página web, tenga cuidado y sea robusto con su programación.

  1. XPath absoluta frente a XPath relativa

Tenga en cuenta que si está anidando XPathSelectors y usa un XPath que comienza con /, ese XPath será absoluto para el documento y no relativo al XPathSelector desde el que lo está llamando.

Cuando haces la operación node.xpath(x_expr), si x_expr comienza con /, es una consulta absoluta, XPath buscará desde root; si no x_expr comienza con ., es una consulta relativa. Esto también se indica en los estándares 2.5 Sintaxis abreviada

. selecciona el nodo de contexto

.//para selecciona los descendientes del elemento para del nodo de contexto

.. selecciona el padre del nodo de contexto

../@lang selecciona el idioma attribute del padre del nodo de contexto

  1. Cómo seguir la página siguiente y el final de la siguiente.

Para su aplicación, probablemente necesite seguir la página siguiente. Aquí, el nodo de la página siguiente es fácil de ubicar: hay botones de siguiente. Sin embargo, también debes cuidar el tiempo para dejar de seguir. Busque cuidadosamente su parámetro de consulta de URL para indicar el patrón de URL de su aplicación. Aquí, para determinar cuándo detenerse, siga la página siguiente, puede comparar el rango de artículos actual con el número total de artículos.

Nueva edición

Estaba un poco confundido con el significado de contenido del enlace. Ahora entendí que @student también quería rastrear el enlace para extraer contenido de AD. La siguiente es una solución.

  1. Enviar solicitud y adjuntar su analizador

Como puede notar, yo uso Scrapy Request clase para seguir la página siguiente. En realidad, el poder de la clase Request está más allá de eso: puede adjuntar la función de análisis deseada para cada solicitud configurando el parámetro callback.

callback (invocable): la función que se llamará con la respuesta de esta solicitud (una vez descargada) como primer parámetro. Para obtener más información, consulte Pasar datos adicionales a funciones de devolución de llamada a continuación. Si una solicitud no especifica una devolución de llamada, se utilizará el método parse () de la araña. Tenga en cuenta que si se generan excepciones durante el procesamiento, en su lugar se llama a errback.

En el paso 3, no configuré callback al enviar solicitudes de página siguiente, ya que estas solicitudes deben manejarse de forma predeterminada parse función. Ahora llega a la página de AD especificada, una página diferente a la anterior página de lista de AD. Por lo tanto, necesitamos definir una nueva función de analizador de página, digamos parse_ad, cuando enviemos cada solicitud de página de AD, adjunte este parse_ad Funcionar con las solicitudes.

Vayamos al código de muestra revisado que me funciona:

items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class ScrapydemoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    link = scrapy.Field()


class AdItem(scrapy.Item):
    title = scrapy.Field()
    description = scrapy.Field()

La araña

# -*- coding: utf-8 -*-
from scrapy.spiders import Spider
from scrapy.http import Request
from scrapydemo.items import ScrapydemoItem
from scrapydemo.items import AdItem
try:
    from urllib.parse import urljoin
except ImportError:
    from urlparse import urljoin


class MySpider(Spider):
    name = "demo"
    allowed_domains = ["craigslist.org"]
    start_urls = ["http://sfbay.craigslist.org/search/npo"]

    def parse(self, response):
        # locate list of each item
        s_links = response.xpath("//*[@id='sortable-results']/ul/li")
        # locate next page and extract it
        next_page = response.xpath(
            '//a[@title="next page"]/@href').extract_first()
        next_page = urljoin(response.url, next_page)
        to = response.xpath(
            '//span[@class="rangeTo"]/text()').extract_first()
        total = response.xpath(
            '//span[@class="totalcount"]/text()').extract_first()
        # test end of following
        if int(to) < int(total):
            # important, send request of next page
            # default parsing function is 'parse'
            yield Request(next_page)

        for s_link in s_links:
            # locate and extract
            title = s_link.xpath("./p/a/text()").extract_first().strip()
            link = s_link.xpath("./p/a/@href").extract_first()
            link = urljoin(response.url, link)
            if title is None or link is None:
                print('Warning: no title or link found: %s', response.url)
            else:
                yield ScrapydemoItem(title=title, link=link)
                # important, send request of ad page
                # parsing function is 'parse_ad'
                yield Request(link, callback=self.parse_ad)

    def parse_ad(self, response):
        ad_title = response.xpath(
            '//span[@id="titletextonly"]/text()').extract_first().strip()
        ad_description = ''.join(response.xpath(
            '//section[@id="postingbody"]//text()').extract())
        if ad_title is not None and ad_description is not None:
            yield AdItem(title=ad_title, description=ad_description)
        else:
            print('Waring: no title or description found %s', response.url)

Nota clave

  • Dos funciones de análisis, parse para solicitudes de la página de lista de AD y parse_ad para la solicitud de la página AD especificada.
  • Para extraer el contenido de la publicación de AD, necesita algunos trucos. Vea ¿Cómo puedo obtener todo el texto sin formato de un sitio web con Scrapy?

Una instantánea de la salida:

2016-11-10 21:25:14 [scrapy] DEBUG: Scraped from <200 http://sfbay.craigslist.org/eby/npo/5869108363.html>
'description': 'n'
                '        n'
                '            QR Code Link to This Postn'
                '            n'
                '        n'
                'Agency History:n' ........
 'title': 'Staff Accountant'
2016-11-10 21:25:14 [scrapy] INFO: Dumping Scrapy stats:
'downloader/request_bytes': 39259,
 'downloader/request_count': 117,
 'downloader/request_method_count/GET': 117,
 'downloader/response_bytes': 711320,
 'downloader/response_count': 117,
 'downloader/response_status_count/200': 117,
 'finish_reason': 'shutdown',
 'finish_time': datetime.datetime(2016, 11, 11, 2, 25, 14, 878628),
 'item_scraped_count': 314,
 'log_count/DEBUG': 432,
 'log_count/INFO': 8,
 'request_depth_max': 2,
 'response_received_count': 117,
 'scheduler/dequeued': 116,
 'scheduler/dequeued/memory': 116,
 'scheduler/enqueued': 203,
 'scheduler/enqueued/memory': 203,
 'start_time': datetime.datetime(2016, 11, 11, 2, 24, 59, 242456)
2016-11-10 21:25:14 [scrapy] INFO: Spider closed (shutdown)

Gracias. Espero que esto sea útil y divertido.

Reseñas y calificaciones de la guía

Te invitamos a favorecer nuestra publicación añadiendo un comentario o valorándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *