在Scrapy上的多个链接中爬行

2024-10-02 08:29:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图首先在这个网站的主页上搜索每年一张表格的链接。然后,我要刮每个网站,同时保持每年的记录

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

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返回一个只包含内容<html></html>的响应。如果有一种方法,响应对象可以类似于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}

Tags: indivcleanfordatadatehtmltable
1条回答
网友
1楼 · 发布于 2024-10-02 08:29:26

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

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

也就是说,您可以对spider进行许多改进

  • 使用scrapy的内置^{}而不是字符串拆分

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

  • 使用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
            }

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

相关问题 更多 >

    热门问题