天天看点

pyspider爬虫教程 (2):AJAX和HTTP

在上一篇教程《pyspider 爬虫教程 (1):html 和 css 选择》中,我们使用 self.crawl api 抓取豆瓣电影的

html 内容,并使用 css 选择器解析了一些内容。不过,现在的网站通过使用 ajax

等技术,在你与服务器交互的同时,不用重新加载整个页面。但是,这些交互手段,让抓取变得稍微难了一些:你会发现,这些网页在抓回来后,和浏览器中的并不相同。你需要的信息并不在返回

html 代码中。

在这一篇教程中,我们会讨论这些技术 和 抓取他们的方法。

ajax

ajax 是 asynchronous javascript and xml(异步的 javascript 和 xml)的缩写。ajax

通过使用原有的 web

标准组件,实现了在不重新加载整个页面的情况下,与服务器进行数据交互。例如在新浪微博中,你可以展开一条微博的评论,而不需要重新加载,或者打开一个新的页面。但是这些内容并不是一开始就在页面中的(这样页面就太大了),而是在你点击的时候被加载进来的。这就导致了你抓取这个页面的时候,并不能获得这些评论信息(因为你没有『展开』)。

ajax 的一种常见用法是使用 ajax 加载 json 数据,然后在浏览器端渲染。如果能直接抓取到 json 数据,会比 html 更容易解析。

当一个网站使用了 ajax 的时候,除了用 pyspider

抓取到的页面和浏览器看到的不同以外。你在浏览器中打开这样的页面,或者点击『展开』的时候,常常会看到『加载中』或者类似的图标/动画。例如,当你尝试抓取:http://movie.douban.com/explore

pyspider爬虫教程 (2):AJAX和HTTP

你会发现电影是『载入中…』

找到真实的请求

由于 ajax 实际上也是通过 http 传输数据的,所以我们可以通过 chrome developer tools 找到真实的请求,直接发起真实请求的抓取就可以获得数据了。

打开一个新窗口

按 ctrl+shift+i (在 mac 上请按 cmd+opt+i) 打开开发者工具。

切换到网络( netwotk 面板)

在窗口中打开 http://movie.douban.com/explore

在页面加载的过程中,你会在面板中看到所有的资源请求。

pyspider爬虫教程 (2):AJAX和HTTP
pyspider爬虫教程 (2):AJAX和HTTP

ajax 一般是通过 xmlhttprequest 对象接口发送请求的,xmlhttprequest 一般被缩写为

xhr。点击网络面板上漏斗形的过滤按钮,过滤出 xhr

请求。挨个查看每个请求,通过访问路径和预览,找到包含信息的请求:http://movie.douban.com/j/searchx61xsubjects?type=movie&tag=%e7%83%ad%e9%97%a8&sort=recommend&page_limit=20&page_start=0

pyspider爬虫教程 (2):AJAX和HTTP

在豆瓣这个例子中,xhr 请求并不多,可以挨个查看来确认。但在 xhr

请求较多的时候,可能需要结合触发动作的时间,请求的路径等信息帮助在大量的请求中找到包含信息的关键请求。这需要抓取或者前端的相关经验。所以,有一个我一直在提的观点,学习抓取的最好方法是:学会写网站。

现在可以在新窗口中打开

http://movie.douban.com/j/searchx67xsubjects?type=movie&tag=%e7%83%ad%e9%97%a8&sort=recommend&page_limit=20&page_start=0,你会看到包含电影数据的

json 原始数据。推荐安装 jsonview(firfox版)插件,这样可以看到更好看的 json 格式,展开折叠列等功能。然后,我们根据

json 数据,编写一个提取电影名和评分的脚本:

class handler(basehandler): 

    def on_start(self): 

        self.crawl('http://movie.douban.com/j/search_subjects?type=movie&tag=%e7%83%ad%e9%97%a8&sort=recommend&page_limit=20&page_start=0', 

                   callback=self.json_parser) 

    def json_parser(self, response): 

        return [{ 

            "title": x['title'], 

            "rate": x['rate'], 

            "url": x['url'] 

        } for x in response.json['subjects']]  

你可以使用 response.json 将结果转为一个 python 的 dict 对象

你可以在 http://demo.pyspider.org/debug/tutorial_douban_explore 获得完整的代码,并进行调试。脚本中还有一个使用 phantomjs 渲染的提取版本,将会在下一篇教程中介绍。

http

http 是用来传输网页内容的协议。在前面的教程中,我们已经通过 self.crawl 接口提交了 url 进行了抓取。这些抓取就是通过 http 协议传输的。

在抓取过程中,你可能会遇到类似 403 forbidden,或者需要登录的情况,这时候你就需要正确的 http 参数进行抓取了。

一个典型的 http 请求包如下,这个请求是发往 http://example.com/ 的:

get / http/1.1 

host: example.com 

connection: keep-alive 

cache-control: max-age=0 

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 

user-agent: mozilla/5.0 (macintosh; intel mac os x 10_10_1) applewebkit/537.36 (khtml, like gecko) chrome/40.0.2214.45 safari/537.36 

referer: http://en.wikipedia.org/wiki/example.com 

accept-encoding: gzip, deflate, sdch 

accept-language: zh-cn,zh;q=0.8 

if-none-match: "359670651" 

if-modified-since: fri, 09 aug 2013 23:54:35 gmt  

请求的第一行包含 method, path 和 http 协议的版本信息

余下的行被称为 header,是以 key: value 的形式呈现的

如果是 post 请求,在请求结尾可能还会有 body 内容

你可以通过前面用过的 chrome developer tools 工具查看到这些信息:

pyspider爬虫教程 (2):AJAX和HTTP

在大多数时候,使用正确的 method, path, headers 和 body 总是能抓取到你需要的信息的。

http method

http method 告诉服务器对 url 资源期望进行的操作。例如在打开一个 url 的时候使用的是 get 方式,而在提交数据的时候一般使用 post。

todo: need example here

http headers

http headers 是请求所带的一个参数列表,你可以在 这里 找到完整的常用 headers 列表。一些常用的需要注意的有:

user-agent

ua 是标识你使用的浏览器,或抓取程序的一段字符串。pyspider 使用的默认 ua 是 pyspider/version

(+http://pyspider.org/)。网站常用这个字符串来区分用户的操作系统和浏览器,以及判断对方是否是爬虫。所以在抓取的时候,常常会对

ua 进行伪装。

在 pyspider 中,你可以通过 self.crawl(url, headers={'user-agent':

'pyspider'}),或者是 crawl_config = {'headers': {'user-agent': 'xxxx'}}

来指定脚本级别的 ua。详细请查看 api 文档。

referer

referer 用于告诉服务器,你访问的上一个网页是什么。常常被用于防盗链,在抓取图片的时候可能会用到。

x-requested-with

当使用 xhr 发送 ajax 请求时会带上的 header,常被用于判断是不是 ajax 请求。例如在 北邮人论坛 中,你需要:

def on_start(self): 

        self.crawl('http://bbs.byr.cn/board/python', 

                   headers={'x-requested-with': 'xmlhttprequest'}, 

                   callback=self.index_page)  

带有 headers={'x-requested-with': 'xmlhttprequest'} 才能抓取到内容。

http cookie

虽然 cookie 只是 http header 中的一个,但是因为非常重要,但是拿出来说一下。cookie 被 http 请求用来区分、追踪用户的身份,当你在一个网站登录的时候,就是通过写入 cookie 字段来记录登录状态的。

当遇到需要登录的网站,你需要通过设置 cookie 参数,来请求需要登录的内容。cookie

可以通过开发者工具的请求面板,或者是资源面板中获得。在 pyspider 中,你也可以使用 response.cookies 获得返回的

cookie,并使用 self.crawl(url, cookie={'key': 'value'}) 来设置请求的 cookie 参数。

作者:佚名

来源:51cto