scrapy可以用于抓取使用AJAX的动态网站内容吗?

167 投票
10 回答
150124 浏览
提问于 2025-04-17 08:34

我最近在学习Python,开始尝试制作一个网络爬虫。这个爬虫并不复杂,它的唯一目的是从一个博彩网站上获取数据,然后把这些数据放到Excel里。

大部分问题都能解决,我也在慢慢摸索。不过,我遇到了一个大难题。如果一个网站加载了一张马匹的表格,并列出了当前的投注价格,这些信息并不在任何源文件里。线索是,这些数据是实时更新的,数字显然是从某个远程服务器上更新过来的。在我电脑上的HTML里,只有一个空洞,那里应该是他们的服务器推送我需要的所有有趣数据。

现在我对动态网页内容的经验不多,所以这个问题让我很困惑。

我觉得Java或者JavaScript可能是关键,这个问题经常提到。

这个爬虫其实就是一个赔率比较引擎。有些网站有API,但我需要的是那些没有API的网站。我正在使用Python 2.7的scrapy库。

如果这个问题太开放,我很抱歉。简而言之,我的问题是:如何使用scrapy来抓取这些动态数据,以便我可以使用它?也就是说,如何实时抓取这些投注赔率的数据?


另见:如何在Python中抓取动态内容(由JavaScript创建)的页面?,这是一般情况。

10 个回答

44

在抓取网页内容的时候,我们常常会遇到一些问题,比如页面上的内容是用JavaScript生成的,这样的话,Scrapy就抓取不到这些内容了(比如通过ajax请求,或者jQuery的各种操作)。

不过,如果你把Scrapy和一个叫Selenium的网页测试工具结合使用,就可以抓取在普通网页浏览器中显示的任何内容。

需要注意的几点:

  • 你必须安装Python版本的Selenium RC,并且要正确设置Selenium。此外,这只是一个基本的抓取模板。你可以做得更复杂、更高级,但我只是想展示一个基本的思路。现在的代码会对每个网址发出两个请求,一个是Scrapy发的,另一个是Selenium发的。我相信有办法让Selenium只发一个请求,但我没有去实现这个。通过发两个请求,你也能用Scrapy抓取页面。

  • 这非常强大,因为现在你可以抓取整个渲染后的DOM(文档对象模型),而且仍然可以使用Scrapy的所有优秀抓取功能。当然,这样抓取会慢一些,但如果你需要渲染后的DOM,等待一下也是值得的。

    from scrapy.contrib.spiders import CrawlSpider, Rule
    from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
    from scrapy.selector import HtmlXPathSelector
    from scrapy.http import Request
    
    from selenium import selenium
    
    class SeleniumSpider(CrawlSpider):
        name = "SeleniumSpider"
        start_urls = ["http://www.domain.com"]
    
        rules = (
            Rule(SgmlLinkExtractor(allow=('\.html', )), callback='parse_page',follow=True),
        )
    
        def __init__(self):
            CrawlSpider.__init__(self)
            self.verificationErrors = []
            self.selenium = selenium("localhost", 4444, "*chrome", "http://www.domain.com")
            self.selenium.start()
    
        def __del__(self):
            self.selenium.stop()
            print self.verificationErrors
            CrawlSpider.__del__(self)
    
        def parse_page(self, response):
            item = Item()
    
            hxs = HtmlXPathSelector(response)
            #Do some XPath selection with Scrapy
            hxs.select('//div').extract()
    
            sel = self.selenium
            sel.open(response.url)
    
            #Wait for javscript to load in Selenium
            time.sleep(2.5)
    
            #Do some crawling of javascript created content with Selenium
            sel.get_text("//div")
            yield item
    
    # Snippet imported from snippets.scrapy.org (which no longer works)
    # author: wynbennett
    # date  : Jun 21, 2011
    

参考链接: http://snipplr.com/view/66998/

104

这里有一个简单的例子,展示了如何用 scrapy 处理 AJAX 请求。我们来看一下这个网站 rubin-kazan.ru

这个网站上的所有留言都是通过 AJAX 请求加载的。我的目标是获取这些留言及其所有属性(比如作者、日期等):

enter image description here

当我分析这个页面的源代码时,发现看不到所有的留言,因为这个网页使用了 AJAX 技术。不过,我可以用 Mozilla Firefox 的 Firebug(或者其他浏览器的类似工具)来分析生成留言的 HTTP 请求:

enter image description here

这个请求不会重新加载整个页面,而只会加载包含留言的部分。为此,我点击页面底部的任意页码:

enter image description here

然后我观察到负责留言内容的 HTTP 请求:

enter image description here

完成后,我分析请求的头部信息(我必须提到,这个 URL 是从源页面的 var 部分提取的,见下面的代码):

enter image description here

还有请求的表单数据内容(HTTP 方法是“Post”):

enter image description here

最后是响应的内容,它是一个 JSON 文件:

enter image description here

这个文件包含了我所需要的所有信息。

接下来,我需要把这些知识应用到 scrapy 中。我们来定义一个爬虫来实现这个目标:

class spider(BaseSpider):
    name = 'RubiGuesst'
    start_urls = ['http://www.rubin-kazan.ru/guestbook.html']

    def parse(self, response):
        url_list_gb_messages = re.search(r'url_list_gb_messages="(.*)"', response.body).group(1)
        yield FormRequest('http://www.rubin-kazan.ru' + url_list_gb_messages, callback=self.RubiGuessItem,
                          formdata={'page': str(page + 1), 'uid': ''})

    def RubiGuessItem(self, response):
        json_file = response.body

parse 函数中,我得到了第一次请求的响应。在 RubiGuessItem 中,我得到了包含所有信息的 JSON 文件。

81

基于Webkit的浏览器(比如谷歌浏览器或Safari)都有内置的开发者工具。在Chrome浏览器中,你可以通过 菜单->工具->开发者工具 来打开它。网络 选项卡可以让你查看每一个请求和响应的所有信息:

在这里输入图片描述

在图片的底部,你可以看到我把请求过滤到了 XHR - 这些是由JavaScript代码发出的请求。

小提示:每次加载页面时,日志都会被清空,图片底部的黑点按钮可以保留日志。

在分析请求和响应后,你可以从你的网络爬虫中模拟这些请求,并提取有价值的数据。在很多情况下,获取数据会比解析HTML更简单,因为这些数据不包含展示逻辑,并且是为JavaScript代码访问而格式化的。

Firefox也有类似的扩展,叫做 firebug。有人会说firebug更强大,但我更喜欢Webkit的简单。

撰写回答