python - Scrapy:抓取多个页面并在单个数组中生成结果

标签 python scrapy

我想做的是抓取多个页面并在单个数组中产生结果。

我找到了this post ,它描述了如何抓取多个页面并从每个抓取的页面生成文本。

我引用了这种方法(并对其进行了一些修改),这是我的蜘蛛看起来像......

from scrapy import Request
from test_project.items import PriceSpiderItem

class RoomsSpider(scrapy.Spider):
    name = 'rooms'
    allowed_domains = ['sample.com']
    start_urls = ['http://sample.com/rooms']

    def parse(self, response):
        for resource in response.xpath('.//*[@class="sample"]'):
            item = PriceSpiderItem()
            item['result'] = resource.xpath("text()").extract_first()
            yield item

        nextUrl = response.xpath('//*[@label="Next"]/@href').extract_first()

        if(nextUrl is not None):
            absoluteNextUrl = response.urljoin(nextUrl)
            yield Request(url=absoluteNextUrl, callback=self.parse)

但是,使用这种方法,结果将如下所示......

{
 "items" : [
  {"result": "blah blah"},
  {"result": "blah blah blah blah blah"},
  {"result": "blah blah blah blah"},
  ...
  etc.
  ...
  {"result": "blah blah blah blah blah"},
  {"result": "blah blah blah"}
 ]
}

这并不是我想要达到的效果。理想情况下,结果将位于单个数组中,例如...

 {
  "items" : [
    "blah blah",
    "blah blah blah blah blah",
    "blah blah blah blah",
     ...
    "blah blah blah blah blah",
    "blah blah blah"
   ]
 }

但是,我不确定它是否可以实现。

据我了解,Scrapy 是非阻塞的,因此我也许能够将结果存储在全局变量中,并在蜘蛛抓取所有页面后生成它。

(也就是说,我不想使用全局变量,因为随着应用程序变得越来越大,维护它可能会很困难)

如有任何建议,我们将不胜感激。

附注

@Wim Hermans 给了我有趣的方法(谢谢!)。

其中,可以使用 ItemPipeline 将结果存储在文件中,并在抓取完所有页面后生成它。

这看起来很有希望,但是如果 Spider 运行在 scrapyrt 上(或类似的东西)作为 REST API 端点工作,我不确定如何处理并发问题。

# 1. Client A makes a request
# 2. Spider receives Client A's request
# 3. Client B makes a request
# 4. Spider receives Client B's request
# 5. Spider fulfills Client B's request, saves the result in "result.csv"
# 6. Spider fulfills Client A's request, updates "result.csv" with Client A's request
# 7. Spider responses with "result.csv" for bot Client A and B

Scrapy 是非阻塞的,所以我想这样的场景可能会发生

P.P.S.

如果您必须产生结果,@Wim Hermans 提出的第一个解决方案可能是最好的解决方案(但要小心内存使用)

最佳答案

我可以想到几种不同的选择来实现这一目标:

  1. 您将结果传递到元中,直到抓取完成:
def parse(self, response):
    result = response.meta.get('result', [])
    for resource in response.xpath('.//*[@class="sample"]'):
        result.append(resource.xpath("text()").extract_first())

    nextUrl = response.xpath('//*[@label="Next"]/@href').extract_first()
    meta = {'result': result}
    if nextUrl:
        absoluteNextUrl = response.urljoin(nextUrl)
        yield Request(url=absoluteNextUrl, callback=self.parse, meta=meta)
    else:
        item = PriceSpiderItem()
        item['result'] = result
        yield item

根据您将获得的数据量,这可能会变得相当繁重。

  • 编写自定义项目管道:
  • 您不会在元中传递完整的结果集,而是编写一个项目管道,将结果保存在列表中并在最后给出结果。

    class CombineResultsPipeline(object):
        def __init__(self):
            self.results = []
    
        def process_item(self, item, spider):
            self.results.append(item['result'])
            return item
    
        def close_spider(self, spider):
            print(f"full result set is {self.results}")
    

    这基本上就像将结果存储在全局变量中一样,因此可能也不是您所需要的。

  • 写入文件/数据库
  • 更节省内存的选项可能是将结果写入文件(或数据库),然后对其进行一些处理以获得所需格式的结果。您可以在项目管道 ( items to json ) 中执行此操作,或者仅使用 Feed Exports ( feed exports )。

    关于python - Scrapy:抓取多个页面并在单个数组中生成结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58043009/

    相关文章:

    python - 根据列值更新值的简洁方法

    python - mysql.connector.errors.DatabaseError : 2005 (HY000): Unknown MySQL server host 'db' (2)

    Python:如何将 Pandas Dataframe 行值转换为单独的列?

    python - 如何用Python绕过Incapsula

    python - scrapy deltafetch 配置不起作用

    python - 数据库变量的语法错误 (MySQL/Python)

    python - scrapy 蜘蛛代码检查

    python - 已安装“opencv-python”但仍显示 'ModuleNotFoundError: No module named cv2 '

    python - 删除空文件

    python-2.7 - 抓取由javascript生成的链接