【问题标题】:Python: Scrapy start_urls list able to handle .format()?Python:Scrapy start_urls 列表能够处理 .format()?
【发布时间】:2015-07-04 08:41:11
【问题描述】:

我想解析股票列表,因此我尝试格式化start_urls 列表的末尾,这样我就可以添加符号而不是整个网址。

stock_list 方法中带有start_urls 的Spider 类:

class MySpider(BaseSpider):
    symbols = ["SCMP"]
    name =  "dozen"
    allowed_domains = ["yahoo.com"]     

def stock_list(stock):
    start_urls = []
    for symb in symbols:
        start_urls.append("http://finance.yahoo.com/q/is?s={}&annual".format(symb))
    return start_urls

def parse(self, response):
    hxs = HtmlXPathSelector(response)
    revenue = hxs.select('//td[@align="right"]')
    items = []
    for rev in revenue:
        item = DozenItem()
        item["Revenue"] = rev.xpath("./strong/text()").extract()
        items.append(item)
    return items[0:3]

如果我去掉 stock_list 并像往常一样做简单的 start_urls,一切都会正常运行,但目前它只会导出一个空文件。

另外,我是否应该尝试 sys.arv 设置,以便在运行 $ scrapy crawl dozen -o items.csv 时只需在命令行中输入股票代码作为参数???

shell 通常会在 LOG/DEBUG 打印输出中打印出 2015-04-25 14:50:57-0400 [dozen] DEBUG: Crawled (200) <GET http://finance.yahoo.com/q/is?s=SCMP+Income+Statement&annual>,但目前不包括它,这意味着它没有正确格式化 start_urls

【问题讨论】:

    标签: python function while-loop web-crawler scrapy


    【解决方案1】:

    实现动态起始 URL 的正确方法是使用 start_request()
    当您拥有起始 URL 的静态列表时,首选做法是使用 start_urls

    start_requests() 这个方法必须返回一个可迭代的,第一个 对此蜘蛛的抓取请求。

    例子:

    class MySpider(BaseSpider):
        name =  "dozen"
        allowed_domains = ["yahoo.com"]
        stock = ["SCMP", "APPL", "GOOG"]
    
        def start_requests(self):
            BASE_URL = "http://finance.yahoo.com/q/is?s={}"
            yield scrapy.Request(url=BASE_URL.format(s)) for s in self.stock
    
        def parse(self, response):
            # parse the responses here
            pass
    

    通过这种方式,您还可以使用生成器而不是预先生成的列表,这样在stock 较大的情况下可以更好地扩展。

    【讨论】:

    • 这是解决问题的首选“pythonic”和“scrapic”方式!
    • @alecxe "scrapic" -- 这是一个新的。我打赌我会再次使用它。 =)
    • @elias 我也会!这个词可以应用于很多事情:)
    • 确实,使用带有多个 URL 的 start_urls,在抓取新页面时会产生随机行为。我不知道start_requests,只是实现了一个新索引,例如:start_urls = [my_urls[0]],然后为每个新页面更新索引。
    • 我不确定你所说的随机行为是什么意思,但如果你说的是爬行的顺序,那并不能保证,因为一切都是异步发生的。
    【解决方案2】:

    我会使用 for 循环,如下所示:

    class MySpider(BaseSpider):
        stock = ["SCMP", "APPL", "GOOG"]
        name =  "dozen"
        allowed_domains = ["yahoo.com"]
        def stock_list(stock):
            start_urls = []
            for i in stock:            
                start_urls.append("http://finance.yahoo.com/q/is?s={}".format(i))
            return start_urls
        start_urls = stock_list(stock)
    

    然后像我在底部那样分配函数调用。


    更新

    使用 Scrapy 0.24

    # -*- coding: utf-8 -*-
    import scrapy
    from scrapy.selector import Selector
    
    class MySpider(scrapy.Spider):
    
        symbols = ["SCMP"]
        name =  "yahoo"
        allowed_domains = ["yahoo.com"]
    
        def stock_list(symbols):
            start_urls = []
            for symb in symbols:
                start_urls.append("http://finance.yahoo.com/q/is?s={}&annual".format(symb))
            return start_urls
        start_urls = stock_list(symbols)
    
        def parse(self, response):
            revenue = Selector(response=response).xpath('//td[@align="right"]').extract()
            print(revenue)
    

    您可能需要调整 xpath 以获得您想要的;它似乎撤回了相当多的东西。但我已经对此进行了测试,并且抓取工作正常。

    【讨论】:

    • 这是完美的并且完全有意义,但会导出一个空的 csv。我认为.format() 不起作用,{} 只是作为 url 包含在内......
    • @CharlesWatson 谢谢,很高兴它有帮助。您是否定义了解析方法并告诉它提取任何内容?我没有看到你提到任何关于上面实际抓取的内容。
    • 我已将我的解析方法添加到帖子中。
    • 我刚刚意识到,我认为您使用的是旧版本的 Scrapy。如果可以,请升级并尝试我在原始答案的编辑中添加的内容。它与旧版本不兼容,但我已经尝试过,并且知道它在最新版本中可以正常工作。
    • 我的外壳显示Starting Scrapy 0.24.6。我是否以某种方式引用了旧语法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 2014-05-17
    • 1970-01-01
    • 2018-06-02
    相关资源
    最近更新 更多