【问题标题】:Scrapy - how to manage cookies/sessionsScrapy - 如何管理 cookie/会话
【发布时间】:2011-06-26 06:29:12
【问题描述】:

我有点困惑 cookie 如何与 Scrapy 一起工作,以及您如何管理这些 cookie。

这基本上是我正在尝试做的简化版本:


网站的运作方式:

当您访问该网站时,您会获得一个会话 cookie。

当您进行搜索时,网站会记住您搜索的内容,因此当您执行诸如转到下一页结果之类的操作时,它会知道它正在处理的搜索。


我的脚本:

我的蜘蛛有一个 searchpage_url 的起始 url

搜索页面由parse() 请求,搜索表单响应被传递给search_generator()

search_generator() 然后yields 大量使用FormRequest 的搜索请求和搜索表单响应。

每个 FormRequest 以及后续的子请求都需要有自己的会话,因此需要有自己的单独 cookiejar 和自己的会话 cookie。


我已经看到文档中有关阻止 cookie 合并的元选项的部分。这实际上是什么意思?这是否意味着发出请求的蜘蛛将在其余生中拥有自己的 cookiejar?

如果 cookie 在每个 Spider 级别上,那么当生成多个 Spider 时它是如何工作的?是否可以只让第一个请求生成器产生新的蜘蛛并确保从那时起只有那个蜘蛛处理未来的请求?

我假设我必须禁用多个并发请求。否则一个蜘蛛会在同一个会话 cookie 下进行多次搜索,而未来的请求只会与最近的搜索有关?

我很困惑,任何澄清都会非常受欢迎!


编辑:

我刚刚想到的另一个选项是完全手动管理会话 cookie,并将其从一个请求传递到另一个请求。

我想这意味着禁用 cookie.. 然后从搜索响应中获取会话 cookie,并将其传递给每个后续请求。

这是你在这种情况下应该做的吗?

【问题讨论】:

标签: python session cookies session-cookies scrapy


【解决方案1】:

我认为最简单的方法是使用搜索查询作为蜘蛛参数(将在构造函数中接收)运行同一蜘蛛的多个实例,以便重用 Scrapy 的 cookie 管理功能。因此,您将拥有多个蜘蛛实例,每个实例都抓取一个特定的搜索查询及其结果。但是你需要自己运行蜘蛛:

scrapy crawl myspider -a search_query=something

或者您可以使用 Scrapyd 通过 JSON API 运行所有蜘蛛。

【讨论】:

  • 与单个蜘蛛生成多个并发请求相比,这不会产生很多额外的开销吗?
  • 嗨 Pablo,我真的需要你的帮助 stackoverflow.com/questions/25353650/… 你在 gmail 群组上帮助了我很多,我希望你在这里帮助我,因为我被困住了
  • @Acorn 那是肯定的。创建和启动整个爬虫实例会产生开销
【解决方案2】:
from scrapy.http.cookies import CookieJar
...

class Spider(BaseSpider):
    def parse(self, response):
        '''Parse category page, extract subcategories links.'''

        hxs = HtmlXPathSelector(response)
        subcategories = hxs.select(".../@href")
        for subcategorySearchLink in subcategories:
            subcategorySearchLink = urlparse.urljoin(response.url, subcategorySearchLink)
            self.log('Found subcategory link: ' + subcategorySearchLink), log.DEBUG)
            yield Request(subcategorySearchLink, callback = self.extractItemLinks,
                          meta = {'dont_merge_cookies': True})
            '''Use dont_merge_cookies to force site generate new PHPSESSID cookie.
            This is needed because the site uses sessions to remember the search parameters.'''

    def extractItemLinks(self, response):
        '''Extract item links from subcategory page and go to next page.'''
        hxs = HtmlXPathSelector(response)
        for itemLink in hxs.select(".../a/@href"):
            itemLink = urlparse.urljoin(response.url, itemLink)
            print 'Requesting item page %s' % itemLink
            yield Request(...)

        nextPageLink = self.getFirst(".../@href", hxs)
        if nextPageLink:
            nextPageLink = urlparse.urljoin(response.url, nextPageLink)
            self.log('\nGoing to next search page: ' + nextPageLink + '\n', log.DEBUG)
            cookieJar = response.meta.setdefault('cookie_jar', CookieJar())
            cookieJar.extract_cookies(response, response.request)
            request = Request(nextPageLink, callback = self.extractItemLinks,
                          meta = {'dont_merge_cookies': True, 'cookie_jar': cookieJar})
            cookieJar.add_cookie_header(request) # apply Set-Cookie ourselves
            yield request
        else:
            self.log('Whole subcategory scraped.', log.DEBUG)

【讨论】:

【解决方案3】:

三年后,我认为这正是您想要的: http://doc.scrapy.org/en/latest/topics/downloader-middleware.html#std:reqmeta-cookiejar

只需在你的蜘蛛的 start_requests 方法中使用类似的东西:

for i, url in enumerate(urls):
    yield scrapy.Request("http://www.example.com", meta={'cookiejar': i},
        callback=self.parse_page)

请记住,对于后续请求,您每次都需要显式重新附加 cookiejar:

def parse_page(self, response):
    # do some processing
    return scrapy.Request("http://www.example.com/otherpage",
        meta={'cookiejar': response.meta['cookiejar']},
        callback=self.parse_other_page)

【讨论】:

  • 我可以配置scrapy为每个请求重新附加cookiejar而不是parse_page吗?
  • 我不确定我是否理解这个问题。上面的代码为 start_requests 中生成的每个请求附加了一个单独的 cookiejar,并将其重新附加到 parse_page 生成的每个请求中。没有cookiejar就没有请求。
  • 为什么不只使用cookies={} 而不是meta={'cookiejar': }
  • @MKatleast3 使用meta={'cookiejar': },Scrapy 将为蜘蛛维护多个独立的 cookie 会话,这正是 OP 所需要的。使用 cookies={},您必须手动维护单独的 cookie 会话并确保它们被传递给正确的请求。
【解决方案4】:
def parse(self, response):
    # do something
    yield scrapy.Request(
        url= "http://new-page-to-parse.com/page/4/",
        cookies= {
            'h0':'blah',
            'taeyeon':'pretty'
        },
        callback= self.parse
    )

【讨论】:

    【解决方案5】:

    Scrapy 实现了一个downloader middleware CookiesMiddleware 来支持cookie。您只需要启用它。它模仿浏览器中 cookiejar 的工作原理。

    • 当请求通过 CookiesMiddleware 时,它会读取此域的 cookie 并将其设置在标头 Cookie 上。
    • 当响应返回时,CookiesMiddleware 读取从服务器发送的响应头 Set-Cookie 上的 cookie。并将其保存/合并到 mw 上的 cookiejar 中。

    我已经看到文档中讨论阻止 cookie 合并的元选项的部分。这实际上是什么意思?这是否意味着发出请求的蜘蛛将在其余生中拥有自己的 cookiejar?

    如果 cookie 在每个 Spider 级别上,那么在生成多个 Spider 时它是如何工作的?

    每个蜘蛛都有其唯一的下载中间件。所以蜘蛛有单独的 cookiejars。

    通常,来自一个 Spider 的所有请求共享一个 cookiejar。但是CookiesMiddleware 可以选择自定义此行为

    • Request.meta["dont_merge_cookies"] = True 告诉 mw 这个请求不会从 cookiejar 中读取 Cookie。并且不要将 Set-Cookie 从 resp 合并到 cookiejar 中。这是一个请求级别开关。
    • CookiesMiddleware 支持多个 cookiejars。您必须控制在请求级别使用哪个 cookiejar。 Request.meta["cookiejar"] = custom_cookiejar_name

    请提供CookiesMiddleware的文档和相关源代码。

    【讨论】:

      猜你喜欢
      • 2012-06-28
      • 2012-02-09
      • 2020-11-03
      • 2017-01-07
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      • 2011-11-30
      相关资源
      最近更新 更多