Scrapy爬行stackoverflow问题匹配多个标签

时间:2015-08-21 06:23:06

标签: python web-scraping web-crawler scrapy

我现在正在尝试scrapy。我在http://doc.scrapy.org/en/1.0/intro/overview.html页面中尝试了示例代码。我尝试用标签“bigdata'”提取最近的问题。一切都运作良好。但当我试图用两个标签提取问题时,大数据'并且' python',结果不正确,问题只有' bigdata'标签出现在结果中。但是在浏览器上我正确地得到了两个标签的问题。请找到以下代码:

import scrapy

class StackOverflowSpider(scrapy.Spider):
    name = 'stackoverflow'
    start_urls = ['https://stackoverflow.com/questions/tagged/bigdata?page=1&sort=newest&pagesize=50']

    def parse(self, response):
        for href in response.css('.question-summary h3 a::attr(href)'):
            full_url = response.urljoin(href.extract())
            yield scrapy.Request(full_url, callback=self.parse_question)

    def parse_question(self, response):
        yield {
            'title': response.css('h1 a::text').extract()[0],
            'votes': response.css('.question .vote-count-post::text').extract()[0],
            'body': response.css('.question .post-text').extract()[0],
            'tags': response.css('.question .post-tag::text').extract(),
            'link': response.url,
        }

当我将start_urls更改为

  

start_urls = [' https://stackoverflow.com/questions/tagged/bigdata+python?page=1&sort=newest&pagesize=50']

结果只包含“大数据”的问题。标签。如何仅使用这两个标签获取问题?

编辑:我认为正在发生的事情是,scrapy会进入带有“bigdata”标签的页面。从我给出的主页面,因为标签是指向该标签的主页面的链接。如何编辑此代码以使scrapy不进入标记页面而只进入该页面中的问题?我尝试使用下面的规则,但结果仍然不对。

rules = (Rule(LinkExtractor(restrict_css='.question-summary h3 a::attr(href)'), callback='parse_question'),)

1 个答案:

答案 0 :(得分:3)

你拥有的网址(以及最初的css规则)是正确的;或者更简单:

start_urls = ['https://stackoverflow.com/questions/tagged/python+bigdata']

this推断,这也有效:

start_urls = ['https://stackoverflow.com/questions/tagged/bigdata%20python']

然而,您遇到的问题是,stackoverflow似乎要求您登录以访问多标记搜索功能。要查看此信息,只需注销stackoverflow会话并在浏览器中尝试相同的URL。它会将您重定向到仅两个标记中的第一个的结果页面。

TL; DR获取多个标签功能的唯一方法似乎是登录(通过会话cookie强制执行)

因此,在使用scrapy时,修复是在执行任何其他操作之前对会话(登录)进行身份验证,然后继续正常解析并且一切正常。为此,您可以使用InitSpider代替Spider并添加适当的登录方法。假设您直接使用StackOverflow登录(而不是通过谷歌等),我能够像预期的那样使用它:

import scrapy
import getpass
from scrapy.spiders.init import InitSpider

class StackOverflowSpider(InitSpider):
    name = 'stackoverflow'
    login_page = 'https://stackoverflow.com/users/login'
    start_urls = ['https://stackoverflow.com/questions/tagged/bigdata+python']

    def parse(self, response):
        ...

    def parse_question(self, response):
        ...

    def init_request(self):
        return scrapy.Request(url=self.login_page, callback=self.login)

    def login(self, response):
        return scrapy.FormRequest.from_response(response,
                    formdata={'email': 'yourEmailHere@foobar.com',
                              'password': getpass.getpass()},
                    callback=self.check_login_response)

    def check_login_response(self, response):
        if "/users/logout" in response.body:
            self.log("Successfully logged in")
            return self.initialized()
        else:
            self.log("Failed login")