【问题标题】:How to parse two different items in scrapy?如何在scrapy中解析两个不同的项目?
【发布时间】:2020-06-07 13:42:27
【问题描述】:

我正在使用 scrapy 2.1 来解析类别结果页面。

我想从该网站上抓取 2 种不同的东西:

  1. 类别信息,例如标题和网址
  2. 该类别页面中的产品项目

第 2 项有效,但我正在努力解决如何实现类别信息的存储。我的第一次尝试是创建另一个 Item Class CatItem:

class CatItem(scrapy.Item):
    title       = scrapy.Field() # char - 
    url         = scrapy.Field() # char - 
    level       = scrapy.Field() # int - 

class ProductItem(scrapy.Item):
    title       = scrapy.Field() # char - 

让我们解析页面:

def parse_item(self, response):

    # save category info
    category = CatItem()
    category['url']     = response.url
    category['title']   = response.url
    category['level']   = 1
    yield category

    # now let's parse all products within that category
    for selector in response.xpath("//article//ul/div[@data-qa-id='result-list-entry']"):

        product = ProductItem()
        product['title']          = selector.xpath(".//a/h2/text()").extract_first()
        yield product

我的管道:

class mysql_pipeline(object):
    def __init__(self):
        self.create_connection()

    def create_connection(self):
        settings = get_project_settings()

    def process_item(self, item, spider):
        self.store_db(item, spider)
        return item

现在我不知道如何继续。 process_item 定义中只有一个“项目”。

如何将类别信息也传递给 store_db 方法?

【问题讨论】:

    标签: scrapy


    【解决方案1】:

    您可以检查管道中的项目类型:

    from your_project.items import CatItem, ProductItem
    
    class YourPipeline(object):
    ...
        def process_item(self, item, spider):
            if isinstance(item, CatItem):
                save_category(item)
            return item
    

    更新简单的 PoC 代码:

    import scrapy
    import csv
    from scrapy.crawler import CrawlerProcess
    
    
    class BooksPipeline(object):
    
        def process_item(self, item, spider):
            filename = None
            if isinstance(item, CategoryItem):
                filename = 'Categories.csv'
            elif isinstance(item, BookItem):
                filename = 'Books.csv'
            with open(filename, 'a', encoding='utf-8') as f:
                writer = csv.DictWriter(f, fieldnames=['Title', 'URL'], lineterminator="\n")
                writer.writerow(item)
            return item
    
    class BooksSpider(scrapy.Spider):
        name = "books"
        start_urls = ['http://books.toscrape.com/']
    
        def parse(self, response):
            for book_url in response.xpath('//ol/li//h3/a/@href').getall():
                yield scrapy.Request(
                    url=response.urljoin(book_url),
                    callback=self.parse_book,
                )
    
        def parse_book(self, response):
            category = CategoryItem()
            category['Title'] = response.xpath('//ul[@class="breadcrumb"]/li[last() - 1]/a/text()').get()
            category['URL'] = response.xpath('//ul[@class="breadcrumb"]/li[last() - 1]/a/@href').get()
            yield category
    
            book = BookItem()
            book['Title'] = response.xpath('//h1/text()').get()
            book['URL'] = response.url
            yield book
    
    class BookItem(scrapy.Item):
        Title = scrapy.Field()
        URL = scrapy.Field()
    
    class CategoryItem(scrapy.Item):
        Title = scrapy.Field()
        URL = scrapy.Field()
    
    if __name__ == "__main__":
        process = CrawlerProcess(
            {
                'USER_AGENT': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36",
                'DOWNLOAD_TIMEOUT':100,
                'ITEM_PIPELINES': {
                    '__main__.BooksPipeline': 300,
                }
            }
        )
    
        process.crawl(BooksSpider)
        process.start()
    

    【讨论】:

    • 听起来不错,但不适用于我的实现。我必须在类或管道中的任何地方声明 CatItem 吗?我试过:#类别还是产品? if isinstance(item, CatItem): print('yes') self.save_category(item, spider) else: print('no') self.store_db(item, spider) 但是该项目永远不会被识别。
    • 当然你需要import你的项目到管道。
    • 我在文件顶部做:from crawler.items import DrugItem, CatItem
    • 知道可能是什么问题吗?从理论上讲,它很快就会起作用。
    • 如果我这样做,我会得到“NoneType”:CatItem 的 print(type(item).__name__),而 ProductItem 被正确报告。那会是什么?
    猜你喜欢
    • 1970-01-01
    • 2012-06-23
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多