Python 网站上的一个格式破坏者阻止了我的痒蜘蛛

Python 网站上的一个格式破坏者阻止了我的痒蜘蛛,python,web-scraping,scrapy,Python,Web Scraping,Scrapy,当我的Scrapy Spider遇到网站格式异常值时,它就会停止工作。以下是出错的网站元素(突出显示的部分): 正确的答案具有“a”属性。如下所示((突出显示的部分)): 这是我的蜘蛛: import scrapy from scrapy.crawler import CrawlerProcess class MySpider(scrapy.Spider): name = "name" allowed_domains = ["website domain"] start_url

当我的Scrapy Spider遇到网站格式异常值时,它就会停止工作。以下是出错的网站元素(突出显示的部分):

正确的答案具有“a”属性。如下所示((突出显示的部分)):

这是我的蜘蛛:

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
  name = "name"
  allowed_domains = ["website domain"]
  start_urls = ['Mywebsite link']

  def parse(self, response):
    self.log('I just visited: ' + response.url)

    for i in response.css('tr.odd'):
        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            'ABN': i.css('td > a::text')[1].extract(),
            'status': i.css('td::text')[2].extract(),
            'size': i.css('td::text')[3].extract(),
            'suburb/town': i.css('td::text')[4].extract(),
            'state': i.css('td::text')[5].extract(),
        }
        yield item

    for i in response.css('tr.even'):
        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            **'ABN': i.css('td > a::text')[1].extract()**,     # this part stops working
            'status': i.css('td::text')[2].extract(),
            'size': i.css('td::text')[3].extract(),
            'suburb/town': i.css('td::text')[4].extract(),
            'state': i.css('td::text')[5].extract(),
        }
        yield item

    # follow pagination link
    next_page_url = response.css('li.next > a::attr(href)').extract_first()
    if next_page_url:
        next_page_url = response.urljoin(next_page_url)
        yield scrapy.Request(url=next_page_url, callback=self.parse)

在网站上看起来是这样的:
该行中的“信息不可用”部分阻止了我的爬行器。请告诉我该怎么做。谢谢大家!

让我们一次只关注一个问题:

使用临时变量,而不是直接输出值

    for i in response.css('tr.even'):
        abn = i.css('td > a::text')[1].extract()
        if not abn:
            abn = 'Unavailable' # Alternatively, you can use a fallback selector

        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            'ABN': abn,
            #...
        }
        yield item
您可能还需要检查
extract()
extract\u first()
的使用情况。实际上,它推荐使用较新的
get()
getall()
,因为这样比较容易混淆

Scrapy用法文档现在使用.get()和.getall()方法编写。 我们认为,这些新方法的结果是更简洁和可读性 代码


让我们一次只关注一个问题:

使用临时变量,而不是直接输出值

    for i in response.css('tr.even'):
        abn = i.css('td > a::text')[1].extract()
        if not abn:
            abn = 'Unavailable' # Alternatively, you can use a fallback selector

        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            'ABN': abn,
            #...
        }
        yield item
您可能还需要检查
extract()
extract\u first()
的使用情况。实际上,它推荐使用较新的
get()
getall()
,因为这样比较容易混淆

Scrapy用法文档现在使用.get()和.getall()方法编写。 我们认为,这些新方法的结果是更简洁和可读性 代码


实现的主要问题是程序可以对不存在的元素调用
extract
方法

for row in response.css('table.views-table tbody tr'):
    i = {}
    # field specific selectors
    i['company_name'], i['ABN'], i['status'], i['size'], i['suburb/town'], i['state'] = row.css('td')
    for key in i.keys():
        i[key] = i[key].css("*::text").get(default="") 
    yield i
我使用列表解包来填充项字段()
,因为表的每一行都有6列

根据-method
get
return result of first match
的说法,这意味着使用此方法,您不需要在表单元格选择器中显式使用
a
标记。

实现的主要问题是,您的程序可以对不存在的元素调用
extract
方法

for row in response.css('table.views-table tbody tr'):
    i = {}
    # field specific selectors
    i['company_name'], i['ABN'], i['status'], i['size'], i['suburb/town'], i['state'] = row.css('td')
    for key in i.keys():
        i[key] = i[key].css("*::text").get(default="") 
    yield i
我使用列表解包来填充项字段()
,因为表的每一行都有6列

根据-method
get
return result of first match
这意味着使用此方法,您不需要在表单元格选择器中显式使用
a
标记。

我通过重写代码解决了此问题。感谢所有的答案贡献者。特别感谢@Gallaecio。以下是我的解决方案:

import scrapy
from scrapy.crawler import CrawlerProcess

class AcncSpider(scrapy.Spider):
  name = "spider_name"
  allowed_domains = ["url"]
  start_urls = ['url']

  def parse(self, response):
    self.log('I just visited: ' + response.url)

    for i in response.css('div.view-content > div > table > tbody > tr.odd'):

        item = {
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first()),
                   
        }
        yield item
    
    for i in response.css('div.view-content > div > table > tbody > tr.even'):

        item = { 
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first())
        }
        yield item
    
    # follow pagination link
    next_page_url = response.css('li.next > a::attr(href)').extract_first()
    if next_page_url:
        next_page_url = response.urljoin(next_page_url)
        yield scrapy.Request(url=next_page_url, callback=self.parse)

我通过重写代码解决了这个问题。感谢所有的答案贡献者。特别感谢@Gallaecio。以下是我的解决方案:

import scrapy
from scrapy.crawler import CrawlerProcess

class AcncSpider(scrapy.Spider):
  name = "spider_name"
  allowed_domains = ["url"]
  start_urls = ['url']

  def parse(self, response):
    self.log('I just visited: ' + response.url)

    for i in response.css('div.view-content > div > table > tbody > tr.odd'):

        item = {
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first()),
                   
        }
        yield item
    
    for i in response.css('div.view-content > div > table > tbody > tr.even'):

        item = { 
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first())
        }
        yield item
    
    # follow pagination link
    next_page_url = response.css('li.next > a::attr(href)').extract_first()
    if next_page_url:
        next_page_url = response.urljoin(next_page_url)
        yield scrapy.Request(url=next_page_url, callback=self.parse)

您的代码在
td
中需要6个链接。输入的HTML应该只有1(而不是公司名称)。考虑从头开始重写你的行提取。谢谢你的回复,但是我不明白你想说什么。你编写了你现在想要修复的代码吗?您了解i.css('td>a::text')[n].extract()在屏幕截图显示输入HTML的情况下所做的工作吗?(注:不鼓励代码截图)url:最上面的代码是实际的网站代码,我的印象是我的循环会抓取td类的文本,并给我法律名称和ABN等信息。您的代码在
td
中需要6个链接。输入的HTML应该只有1(而不是公司名称)。考虑从头开始重写你的行提取。谢谢你的回复,但是我不明白你想说什么。你编写了你现在想要修复的代码吗?您了解i.css('td>a::text')[n].extract()在屏幕截图显示输入HTML的情况下所做的工作吗?(注:不鼓励代码截图)url:最上面的代码是实际的网站代码,我的印象是我的循环会抓取td类的文本,并给我诸如合法名称和名称等信息,但是你是在复制原始代码的主要问题,这是滥用
[n]
。因此,我应该尝试将tr类用作n,然后提取信息,而不是逐个查看。@Upendra感谢您的回复,但是if not条件仍然会导致错误。不过,您正在用原始代码再现主要问题,这就是误用
[n]
。因此,我应该尝试将tr类用作n,然后提取信息,而不是逐个查看。@Upendra感谢您的回复,但是if not条件仍然会导致错误。感谢您的回复,您的代码向我展示了使用Scrapy的一种简洁方法。但是,结果缺少公司名称和ABN。谢谢您的回复,您的代码向我展示了使用Scrapy的简洁方法。然而,结果却丢失了公司名称和ABN。