很多时候,我们要查看的内容必须要先登录才能找到,比如知乎的回答,QQ空间的好友列表、微博上关注的人和粉丝等。要使用爬虫直接登录抓取这些信息时,有一个不太好解决的难题,就是这些网站设置的登录规则以及登录时的验证码识别。不过,我们可以想办法绕过去,思路是这样的:先使用浏览器登录,从浏览器获取登录后的“凭证”,然后将这个“凭证”放到爬虫里,模拟用户的行为继续抓取。这里,我们要获取的凭证就是cookie信息。 这次我们尝试使用python和cookie来抓取QQ空间上的好友列表。使用的工具是FireFox浏览器、FireBug和Python。 获取cookie 打开FireFox浏览器,登录QQ空间,启动FireBug,选择FireBug中的Cookies页签,点击页签中的cookies按钮菜单,选择“导出本站点的cookie”即可完成cookie的导出。 导出cookie会以一个名为cookies.txt文本文件形式存在。 程序实现 然后我们会使用获取的cookie新建一个opener来替换之前请求时使用的默认的opener。将获取的cookies拷贝到程序目录下,编写脚本如下: 因为我们使用的是FireFox浏览器导出的cookie文件,所以这里使用的cookieJar是MozillaCookieJar。 执行脚本…然而报错了: 问题出在cookies文件上,说是不像一个Netscape格式的cookie文件。不过也好解决,只需要在cookies文件开始一行添加如下内容即可: 通过这行内容提示python cookie解析器这是一个FireFox浏览器适用的cookie。 再次执行,还是会报错,因为比较长我就只贴关键的部分出来: 意思是cookie中某些行存在格式错误。具体错在哪儿,需要先了解下FireFox浏览器的cookie格式。MozillaCookieJar认为每行cookie需要包含以下信息,每条信息以制表符分隔: 名称 domain domain_specified path secure expires name value 类型 字符串 布尔型 字符串 布尔型 长整型 字符串 字符串 说明 域名 — 适用路径 是否使用安全协议 过期时间 名称 值 其中domain_specified是什么意思我不很清楚,以后弄明白了再补上。再来看看我们获取的cookie的部分行: 前两行格式是错误的,后两行格式是正确的。前两行缺少“expires”属性。该怎么办呢——补上就好了呗。在其他的cookie中随意选一个时间补上就OK了。 补全cookie后,再次执行是正常的,没有报错。但是没有如预期的打印出好友信息,因为网址错了。使用firebug可以找出正确的网址: 这样就抓取到好友列表了。好友列表是一个json字符串。 至于如何解析json,会在下一节进行说明。 动态获取cookie cookie是有过期时间的。如果想长时间抓取网页,就需要每隔一段时间就更新一次cookie。如果都是从FireFox浏览器来手动获取显得有些笨了。从浏览器获取的cookie只是作为一个入口,之后再进行请求还是要依靠python主动获取cookie。下面是一段获取cookie的程序: 在示例程序中演示了如何获取cookie,并打印了cookie的name和value两项属性。通过实例可以看到每次执行http请求都会重新获取cookie,因此可以将我们的程序调整一下:执行第一次请求时使用我们通过浏览器获取的cookie,之后的每次请求都可以使用上次请求时获取的cookie。调整后的程序: 就这样。 其他 其实在登录QQ空间时使用cookie还有另一种法子——通过观察,也可以在http 请求头中添加cookie信息。 获取请求头中cookie的方式:打开FireFox浏览器,打开FireBug并激活FireBug的network页签,在FireFox浏览器上登录QQ空间,然后在FireBug中找到登录页请求,然后就可以找到请求头中的cookie信息了。 将cookie信息整理成一行,添加到请求头中就可以直接访问了。这个方法相对简单,减少了修改cookie文件的步骤。 此外,在一篇博客文章中还找到了直接登录QQ空间的方案。这算是已知最好的法子了,只要腾讯不改变登录规则就能很简单的执行请求获取cookie。
[阅读更多...]-
Python网络爬虫7 – 使用cookie
-
Python网络爬虫6 – 网页编码
在抓取网页时遇到了一段报错信息: 抓取网页的代码及网址如下: 在错误信息中提示了网页的编码不是utf-8。那么如何确认网页的编码形式呢?有如下几种方式: 从网页源码中查找chaset信息; 使用FireBug。重新打开网页,使用FireBug的NetWork抓取网页加载过程,查看目标网页的头信息,找到Content-Type,其中的charset信息就是; 使用Firefox右键菜单中的“查看页面信息”功能:点击网页空白处 –> 右键菜单 –> 查看页面信息,在弹出窗口中选择 常规 –> 文字编码 也可以查看网页编码信息。 检测到网页的编码是gbk。修改后就可以了。 #########
[阅读更多...] -
Python网络爬虫5 – 图片抓取
这一节看下如何抓取网页中的图片。目标网址是:http://pp.163.com/longer-yowoo/pp/10069141.html。这里有一组我非常喜欢的图片。 要抓取网页首先就要找出图片的网址。这里仍然是使用BeautifulSoup,具体如何使用在前一节《使用BeautifulSoup解析网页》时说过,现在就不说了。看下代码好了: 在上面的代码中soup.select(“img[data-lazyload-src]”)一句查询了所有包含data-lazyload-src属性的img标签。在捕捉到图片标签后,又取出data-lazyload-src属性并打印了出来,一共有六个。 然后就是如何抓取图片了。先来看看之前的一段代码: 这段代码的作用是抓取网页内容并转换为字符串。其中,response是http反馈信息,read方法的作用是读取出http返回的字节流,decode则是将字节流转换为字符串。字符串本质是字节流,图片也是。那么,如何获取图片也就清楚了:就是通过http获取到图片的字节流,再将字节流保存到硬盘即可。看下是如何实现的: 注意open方法中的mode属性“wb”,w指的是写文件,b指的是采用二进制模式。 再来看看完整的程序: 上面的代码仍可以优化下:要下载的文件的名称及扩展名最好是从下载链接中动态获取。这里我偷了个懒,随意指定了文件的名称,扩展名则是早已经知道了。 ###################
[阅读更多...] -
Python网络爬虫4 – 多线程抓取
之前的内容已经大致实现了如何获取网页、分析网页、获取目标内容。接下来的目标是如何让网页抓取进行得更效率些。在进行抓取的时候,时间的消耗主要是在请求等待的时间上,所以一个最容易想到的优化方式就是使用多线程。 多线程 多线程的实现还是比较简单的,下面是一个简单的线程实现方案: 就是这么简单。 线程池 在抓取网页的时候,一个简单的思路就是为每个网页启动一个线程。在要抓取的网页比较少的时候——比如百十来个——这样子还是可行的。但是网页比较多的时候,这样做就不太合理了。因为线程的创建启动和运行都会消耗很多的资源,线程启动太多会耗尽资源导致机器卡死。而且,创建线程后只执行一次也是一种浪费。为了减少线程的创建、实现线程的重复利用,我们需要引入线程池。 可以使用python的ThreadPoolExecutor来创建线程池: 也很简单,甚至不比单线程多一行代码。在代码里创建了一个总数为64的线程池,然后在一个循环中每次取出一条线程来执行func函数,没有空闲线程时则会进入等待。 按照这样的思路,我们也可以使用Queue来自己创建线程池: 在上面的代码里创建了一个长度为5的队列,然后参照队列的长度创建了几个线程,并立刻启动。每个线程随时待命,一旦队列里面有了要执行的任务就会拿过来立即执行,并在执行完成后发送通知给队列。queue.join()方法则会在队列中的所有任务执行完成前阻塞住线程,待所有任务执行完成后再继续执行后面的代码。 并行 前面所述的方案是并发处理的方案。并发处理的方案可以充分利用CPU。不过现在的CPU通常都是多核的,为了利用多核CPU的特点,可以考虑使用并行处理的方案。下面是一个进程的演示: 当然也有对应的进程池了: 在我使用爬虫的经历中极少会用到多进程或进程池。不过,既然说起来了就得说个全套,所以才耐着性子把这块儿写完。 很多人可能就是因为要学习爬虫才开始看Python的。不过看了python却只知道爬虫未免有些可惜,我还是希望能够多接触到一些较深入的东西的。多线程和多进程是学习Python的经历中无论如何也不应该绕过的部分,如果不想浅尝而止的话,还是建议多看看。 完整的抓取程序在下面。程序写于半年前,有很多不成熟的地方,也没心思修改了,凑合看吧。因为代码太长所以折叠了起来: 参考文档 python cookbook:http://python3-cookbook.readthedocs.io/zh_CN/latest/c12/p07_creating_thread_pool.html Python 并发编程之使用多线程和多处理器:http://developer.51cto.com/art/201405/438178.htm ####################
[阅读更多...] -
Python网络爬虫2 – 请求中遇到的几个问题
这次尝试下怎样搜索电影并解析出磁力链接信息。 搜索的网址是:https://www.torrentkitty.tv/search/。 开始了! 使用FireFox打开上面的网址,输入要搜索的电影。在点击搜索按钮前记得打开FireBug,并激活“网络”页签。 查看了请求的详情有些哭笑不得:点击搜索按钮后网页跳转到了这样的地址:https://www.torrentkitty.tv/search/蝙蝠侠/——很明显的REST风格的请求。这样,我们要搜什么内容直接将要搜索的内容拼装到请求地址中就行了。搜索的代码是这样的: 执行后报错了,报错信息如下: 根据错误栈信息可以看出是在发送http请求时报错的,是因为编码导致的错误。在python中使用中文经常会遇到这样的问题。因为是在http请求中出现的中文编码异常,所以可以考虑使用urlencode加密。 在python中对字符串进行urlencode使用的是parse库的quote方法,而非是urlencode方法: 再次执行请求,依然报错了: 报的是HTTP 403错误。这样的错误我遇到过几次,一般是因为没有设置UserAgnet,是网站屏蔽爬虫抓取的一种方式。通过FireBug可以从headers中获取到User-Agent信息: 获取到header信息后再调整下我们的代码,这次会需要使用一个新的类Request: 修改后依然在报错: 请求超时了,估计是因为网站在境外的缘故。所以还需要设置一个请求超时时间,只需要添加一个参数: 这样调整后终于请求成功了。需要强调下,这里的超时设置的时间单位是秒。 总结下吧,这次一共遇到了三个问题: 中文编码的问题; HTTP403错误的问题; 请求超时时间设置的问题。 完整的代码在这里,稍稍作了些调整,还添加了post请求的代码。在pot请求的代码中对字典型的参数调用了urlencode方法: 就是这样。这次本来是想说些关于网页解析的内容的,不过后来发现还是有很多的内容需要先说明下才好进行下去。关于网页解析的内容就挪到了下一节。 这里有篇文章不错,说明了urllib中几个常见的问题:http://www.cnblogs.com/ifso/p/4707135.html ##########
[阅读更多...] -
Python网络爬虫1 – 简单的Http请求
最近这段时间会有需要写一个网络爬虫。会在这里将实现网络爬虫的经验记录下来。 爬虫什么的,只是一个名字罢了。简单地说,也都是从http请求开始的。 Python实现http请求主要依赖的是urllib.request模块。例如发送http get请求: 就是这么简单。 通常,在命令行打印出来的是网页的源代码。想从中过滤出来需要的信息需要进行匹配和筛选。比如使用正则式匹配获取title和body中的内容: 对于一些采集程序来说做到这里就够了。如果我们要的是网页的内容而非网页的html,则需要使用比正则表达式更强大的工具。在下一节会用一个实例介绍相关的内容。 附上完整的程序: #########
[阅读更多...]