使用Scrapy进行认证用户会话抓取

67 投票
1 回答
70383 浏览
提问于 2025-04-16 16:47

Scrapy 文档中,有一个例子说明了如何在 Scrapy 中使用经过身份验证的会话:

class LoginSpider(BaseSpider):
    name = 'example.com'
    start_urls = ['http://www.example.com/users/login.php']

    def parse(self, response):
        return [FormRequest.from_response(response,
                    formdata={'username': 'john', 'password': 'secret'},
                    callback=self.after_login)]

    def after_login(self, response):
        # check login succeed before going on
        if "authentication failed" in response.body:
            self.log("Login failed", level=log.ERROR)
            return

        # continue scraping with authenticated session...

我已经把这个搞定了,没问题。但我想问的是:要如何才能继续使用经过身份验证的会话进行抓取,正如最后一行的评论所说的那样?

1 个回答

74

在上面的代码中,FormRequest用来进行登录认证,它设置了一个叫after_login的函数作为回调。这意味着,当登录尝试完成后,after_login函数会被调用,并且会传入登录后得到的页面。

接下来,它会检查你是否成功登录,方法是查看页面中是否包含特定的字符串,这里是"authentication failed"。如果找到了这个字符串,说明登录失败,程序就结束了。

一旦程序走到这一步,它就知道你已经成功登录了,这时你可以开始发送新的请求或者抓取数据。所以在这个情况下:

from scrapy.selector import HtmlXPathSelector
from scrapy.http import Request

# ...

def after_login(self, response):
    # check login succeed before going on
    if "authentication failed" in response.body:
        self.log("Login failed", level=log.ERROR)
        return
    # We've successfully authenticated, let's have some fun!
    else:
        return Request(url="http://www.example.com/tastypage/",
               callback=self.parse_tastypage)

def parse_tastypage(self, response):
    hxs = HtmlXPathSelector(response)
    yum = hxs.select('//img')

    # etc.

如果你查看 这里,你会看到一个在抓取之前先进行认证的爬虫示例。

在这个示例中,它在parse函数中处理这些事情(这是任何请求的默认回调)。

def parse(self, response):
    hxs = HtmlXPathSelector(response)
    if hxs.select("//form[@id='UsernameLoginForm_LoginForm']"):
        return self.login(response)
    else:
        return self.get_section_links(response)

所以,每当发起一个请求时,程序会检查响应中是否有登录表单。如果有,那就说明需要登录,于是调用相应的函数;如果没有,就调用负责从响应中抓取数据的函数。

希望这些解释清楚了,如果你还有其他问题,随时问我!


编辑:

好的,你想做的不仅仅是发起一个请求并抓取数据。你还想跟踪链接。

要做到这一点,你只需要从页面中抓取相关的链接,然后用这些网址发起请求。例如:

def parse_page(self, response):
    """ Scrape useful stuff from page, and spawn new requests

    """
    hxs = HtmlXPathSelector(response)
    images = hxs.select('//img')
    # .. do something with them
    links = hxs.select('//a/@href')

    # Yield a new request for each link we found
    for link in links:
        yield Request(url=link, callback=self.parse_page)

如你所见,它会为页面上的每个网址发起一个新的请求,而每个请求都会调用同样的函数来处理响应,这样就形成了一种递归抓取的方式。

我上面写的只是一个示例。如果你想要“爬取”页面,建议你查看 CrawlSpider,而不是手动处理这些事情。

撰写回答