scrapy可以用于抓取使用AJAX的动态网站内容吗?
我最近在学习Python,开始尝试制作一个网络爬虫。这个爬虫并不复杂,它的唯一目的是从一个博彩网站上获取数据,然后把这些数据放到Excel里。
大部分问题都能解决,我也在慢慢摸索。不过,我遇到了一个大难题。如果一个网站加载了一张马匹的表格,并列出了当前的投注价格,这些信息并不在任何源文件里。线索是,这些数据是实时更新的,数字显然是从某个远程服务器上更新过来的。在我电脑上的HTML里,只有一个空洞,那里应该是他们的服务器推送我需要的所有有趣数据。
现在我对动态网页内容的经验不多,所以这个问题让我很困惑。
我觉得Java或者JavaScript可能是关键,这个问题经常提到。
这个爬虫其实就是一个赔率比较引擎。有些网站有API,但我需要的是那些没有API的网站。我正在使用Python 2.7的scrapy库。
如果这个问题太开放,我很抱歉。简而言之,我的问题是:如何使用scrapy来抓取这些动态数据,以便我可以使用它?也就是说,如何实时抓取这些投注赔率的数据?
另见:如何在Python中抓取动态内容(由JavaScript创建)的页面?,这是一般情况。
10 个回答
在抓取网页内容的时候,我们常常会遇到一些问题,比如页面上的内容是用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
这里有一个简单的例子,展示了如何用 scrapy
处理 AJAX 请求。我们来看一下这个网站 rubin-kazan.ru。
这个网站上的所有留言都是通过 AJAX 请求加载的。我的目标是获取这些留言及其所有属性(比如作者、日期等):
当我分析这个页面的源代码时,发现看不到所有的留言,因为这个网页使用了 AJAX 技术。不过,我可以用 Mozilla Firefox 的 Firebug(或者其他浏览器的类似工具)来分析生成留言的 HTTP 请求:
这个请求不会重新加载整个页面,而只会加载包含留言的部分。为此,我点击页面底部的任意页码:
然后我观察到负责留言内容的 HTTP 请求:
完成后,我分析请求的头部信息(我必须提到,这个 URL 是从源页面的 var 部分提取的,见下面的代码):
还有请求的表单数据内容(HTTP 方法是“Post”):
最后是响应的内容,它是一个 JSON 文件:
这个文件包含了我所需要的所有信息。
接下来,我需要把这些知识应用到 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 文件。
基于Webkit的浏览器(比如谷歌浏览器或Safari)都有内置的开发者工具。在Chrome浏览器中,你可以通过 菜单->工具->开发者工具
来打开它。网络
选项卡可以让你查看每一个请求和响应的所有信息:
在图片的底部,你可以看到我把请求过滤到了 XHR
- 这些是由JavaScript代码发出的请求。
小提示:每次加载页面时,日志都会被清空,图片底部的黑点按钮可以保留日志。
在分析请求和响应后,你可以从你的网络爬虫中模拟这些请求,并提取有价值的数据。在很多情况下,获取数据会比解析HTML更简单,因为这些数据不包含展示逻辑,并且是为JavaScript代码访问而格式化的。
Firefox也有类似的扩展,叫做 firebug。有人会说firebug更强大,但我更喜欢Webkit的简单。