【问题标题】:Crawling through multiple links on Scrapy通过 Scrapy 上的多个链接爬行
【发布时间】:2021-08-09 03:37:28
【问题描述】:

我正在尝试首先爬取该网站的主页,以获取指向每年表格的链接。然后我想抓取每个站点,同时保持每年的记录。

到目前为止,我的蜘蛛构造为:

div = response.xpath('//*[@id="sidebar"]/div[1]/nav/ul/li[5]/div')
    
hrefs = div.xpath('*//a').extract()
splits = {}
    
for href in hrefs:
    split = href.split('"')
    link = split[1]
    date = split[2]
    clean_date = "".join(re.findall("[^><a/]",date))
    clean_link = "http://www.ylioppilastutkinto.fi" + str(link)
    splits[clean_date] = clean_link

然后,我想使用以下逻辑浏览此文件中的每个链接并爬取它们:

table = resp.xpath('//*[@id="content"]/table/tbody')
rows = table.xpath('//tr')
        
data_dict = {"Category": 
            [w3lib.html.remove_tags(num.get()) for num in rows[0].xpath('td')[1:]]
            }

for row in rows[1:]:
    data = row.xpath('td')
    title = w3lib.html.remove_tags(data[0].get())
    nums = [w3lib.html.remove_tags(num.get()) for num in data[1:]]
    data_dict[title] = nums

我的问题是我找不到有效的方法。在 url 上调用 scrapy.Request 会返回一个仅包含内容 &lt;html&gt;&lt;/html&gt; 的响应。如果有一种方法可以使响应对象类似于 Scrapy shell 中的 fetch 命令给出的对象,那将是理想的,因为我已将选择逻辑基于使用该命令进行测试。

编辑:

这是到目前为止的整个蜘蛛

这个想法是运行第一个 for 循环以获取链接,然后运行第二个 for 循环以从所述链接中提取表。

import scrapy
import regex as re
from scrapy.http import HtmlResponse
import w3lib.html

class MainSpider(scrapy.Spider):
    name = 'links'
    allowed_domains = ['www.ylioppilastutkinto.fi/ylioppilastutkinto/pisterajat']
    start_urls = ['https://www.ylioppilastutkinto.fi/ylioppilastutkinto/pisterajat/']

    def parse(self, response):
        div = response.xpath('//*[@id="sidebar"]/div[1]/nav/ul/li[5]/div')
        
        hrefs = div.xpath('*//a').extract()
        splits = {}
        
        for href in hrefs:
            split = href.split('"')
            link = split[1]
            date = split[2]
            clean_date = "".join(re.findall("[^><a/]",date))
            clean_link = "http://www.ylioppilastutkinto.fi" + str(link)
            splits[clean_date] = clean_link

        
        for date,url in splits.items():
            resp = HtmlResponse(url)
            
            table = resp.xpath('//*[@id="content"]/table/tbody')
            rows = table.xpath('//tr')
        
            data_dict = {"Category":[w3lib.html.remove_tags(num.get()) for num in rows[0].xpath('td')[1:]]}

            for row in rows[1:]:
                data = row.xpath('td')
                title = w3lib.html.remove_tags(data[0].get())
                nums = [w3lib.html.remove_tags(num.get()) for num in data[1:]]
                data_dict[title] = nums
                
        
                yield {
                    'Date': date,
                    'Scores': data_dict}

【问题讨论】:

  • 不清楚您从哪个网址开始?你能发布你的完整蜘蛛吗?
  • fetch 所做的是使用 scrapy.Request 请求 URL。你能展示一下你目前掌握的蜘蛛代码吗?
  • 我添加了蜘蛛的其余部分。
  • 您需要yieldRequest。你做过scrapy tutorial吗?

标签: python html web-scraping xpath scrapy


【解决方案1】:

初始化HtmlResponse(url) 不会完成任何事情,因为类本身不会发出请求。

要将请求添加到scrapy的调度程序,您需要产生一个,例如:yield scrapy.Request(url, callback=self.parse)

话虽如此,您可以对蜘蛛进行许多改进。

  • 使用scrapy的内置LinkExtractor代替字符串分割

  • 使用 css 选择器而不是硬编码的 xpaths

  • 使用selector.root.text 而不是w3lib.remove_tags(完全删除依赖)

这是一个工作示例:

import scrapy
from scrapy.linkextractors import LinkExtractor


class MainSpider(scrapy.Spider):
    name = 'links'
    allowed_domains = ['www.ylioppilastutkinto.fi']
    start_urls = ['https://www.ylioppilastutkinto.fi/ylioppilastutkinto/pisterajat/']

    def parse(self, response):
        le = LinkExtractor(
            allow_domains=self.allowed_domains,
            restrict_xpaths='//*[@id="sidebar"]/div[1]/nav/ul/li[5]/div',
        )
        for link in le.extract_links(response):
            yield scrapy.Request(
                url=link.url,
                callback=self.parse_table,
                cb_kwargs={ 'date': link.text },
            )

    def parse_table(self, response, date):
        rows = response.css('#content table tbody tr')
        if not rows:
            print(f'No table found for url: {response.url}')
            return

        category = [char.root.text for char in rows[0].css('td strong')[1:]]
        if not category:
            category = [char.root.text for char in rows[0].css('td')[1:]]

        for row in rows[1:]:
            cols = row.css('td')
            title = cols[0].root.text
            nums = [col.root.text for col in cols[1:]]
            yield {
                'Date': date,
                'Category': category,
                title: nums
            }

请注意,您的类别解析似乎不起作用。我不确定你要提取什么,所以我把那个留给你。

【讨论】:

  • 好的,花了一些时间来测试和运行建议的想法,是的,一切都很好。感谢您的帮助。也让我对 Scrapy 进行了更多的研究,以改进以前的蜘蛛。另外,是的,我还没有真正研究过表格提取,因为我主要担心的是首先让蜘蛛出现在这些网站上。
猜你喜欢
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 2013-11-30
  • 2016-08-03
相关资源
最近更新 更多