分享

Python3网络爬虫(三): 伪装浏览器

xioaxu790 发表于 2014-10-29 12:29:37 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 10116
问题导读
1、程序如何伪装成浏览器正规军?
2、 http 的 meta 是怎样实现跳转的?
3、怎样保存抓回来的报文?



本文接上一篇:Python 3开发网络爬虫(二)

上一次我自学爬虫的时候, 写了一个简陋的勉强能运行的爬虫alpha. alpha版有很多问题. 比如一个网站上不了, 爬虫却一直在等待连接返回response, 不知道超时跳过; 或者有的网站专门拦截爬虫程序, 我们的爬虫也不会伪装自己成为浏览器正规部队; 并且抓取的内容没有保存到本地, 没有什么作用. 这次我们一个个解决这些小问题.

此外, 在我写这系列文章的第二篇的时候, 我还是一个对http的get和post以及response这些名词一无所知的人, 但是我觉得这样是写不好爬虫的. 于是我参考了 <<计算机网络–自顶向下方法>> 这本书的第二章的大部分内容. 如果你也一样对http的机制一无所知, 我也推荐你找一找这方面的资料来看. 在看的过程中, 安装一个叫做Fiddler的软件, 边学边实践, 观察浏览器是如何访问一个网站的, 如何发出请求, 如何处理响应, 如何进行跳转, 甚至如何通过登录认证. 有句老话说得好, 越会用Fiddler, 就对理论理解更深刻; 越对理论理解深刻, Fiddler就用得越顺手. 最后我们在用爬虫去做各种各样的事情的时候, Fiddler总是最得力的助手之一.

添加超时跳过功能

首先, 我简单地将
  1. urlop = urllib.request.urlopen(url)
  2. 改为
  3. urlop = urllib.request.urlopen(url, timeout = 2)
复制代码

运行后发现, 当发生超时, 程序因为exception中断. 于是我把这一句也放在try .. except 结构里, 问题解决.


支持自动跳转

在爬 http://baidu.com 的时候, 爬回来一个没有什么内容的东西, 这个东西告诉我们应该跳转到 http://www.baidu.com . 但是我们的爬虫并不支持自动跳转, 现在我们来加上这个功能, 让爬虫在爬 baidu.com 的时候能够抓取 www.baidu.com 的内容.

首先我们要知道爬 http://baidu.com 的时候他返回的页面是怎么样的, 这个我们既可以用 Fiddler 看, 也可以写一个小爬虫来抓取. 这里我抓到的内容如下, 你也应该尝试一下写几行 python 来抓一抓.
  1. <html>
  2. <meta http-equiv=”refresh” content=”0;url=http://www.baidu.com/”>
  3. </html>
复制代码


看代码我们知道这是一个利用 html 的 meta 来刷新与重定向的代码, 其中的0是等待0秒后跳转, 也就是立即跳转. 这样我们再像上一次说的那样用一个正则表达式把这个url提取出来就可以爬到正确的地方去了. 其实我们上一次写的爬虫已经可以具有这个功能, 这里只是单独拿出来说明一下 http 的 meta 跳转.

伪装浏览器正规军

前面几个小内容都写的比较少. 现在详细研究一下如何让网站们把我们的Python爬虫当成正规的浏览器来访. 因为如果不这么伪装自己, 有的网站就爬不回来了. 如果看过理论方面的知识, 就知道我们是要在 GET 的时候将 User-Agent 添加到header里.

如果没有看过理论知识, 按照以下关键字搜索学习吧 :D

HTTP 报文分两种: 请求报文和响应报文
请求报文的请求行与首部行
GET, POST, HEAD, PUT, DELETE 方法
我用 IE 浏览器访问百度首页的时候, 浏览器发出去的请求报文如下:
  1. GET http://www.baidu.com/ HTTP/1.1
  2. Accept: text/html, application/xhtml+xml, */*
  3. Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3
  4. User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
  5. Accept-Encoding: gzip, deflate
  6. Host: www.baidu.com
  7. DNT: 1
  8. Connection: Keep-Alive
  9. Cookie: BAIDUID=57F4D171573A6B88A68789EF5DDFE87:FG=1; uc_login_unique=ccba6e8d978872d57c7654130e714abd; BD_UPN=11263145; BD
复制代码



然后百度收到这个消息后, 返回给我的的响应报文如下(有删节):
  1. HTTP/1.1 200 OK
  2. Date: Mon, 29 Sep 2014 13:07:01 GMT
  3. Content-Type: text/html; charset=utf-8
  4. Connection: Keep-Alive
  5. Vary: Accept-Encoding
  6. Cache-Control: private
  7. Cxy_all: baidu+8b13ba5a7289a37fb380e0324ad688e7
  8. Expires: Mon, 29 Sep 2014 13:06:21 GMT
  9. X-Powered-By: HPHP
  10. Server: BWS/1.1
  11. BDPAGETYPE: 1
  12. BDQID: 0x8d15bb610001fe79
  13. BDUSERID: 0
  14. Set-Cookie: BDSVRTM=0; path=/
  15. Set-Cookie: BD_HOME=0; path=/
  16. Content-Length: 80137
  17. <!DOCTYPE html><!–STATUS OK–><html><head><meta http-equiv=”content-type” content=”text/html;charset=utf-8″><meta http-equiv=”X-UA-Compatible” content=”IE=Edge”><link rel=”dns-prefetch” href=”//s1.bdstatic.com”/><link rel=”dns-prefetch” href=”//t1.baidu.com”/><link rel=”dns-prefetch” href=”//t2.baidu.com”/><link rel=”dns-prefetch” href=”//t3.baidu.com”/><link rel=”dns-prefetch” href=”//t10.baidu.com”/><link rel=”dns-prefetch” href=”//t11.baidu.com”/><link rel=”dns-prefetch” href=”//t12.baidu.com”/><link rel=”dns-prefetch” href=”//b1.bdstatic.com”/><title>百度一下,你就知道</title><style index=”index” > ……….这里省略两万字……………. </script></body></html>
复制代码


如果能够看懂这段话的第一句就OK了, 别的可以以后再配合 Fiddler 慢慢研究. 所以我们要做的就是在 Python 爬虫向百度发起请求的时候, 顺便在请求里面写上 User-Agent, 表明自己是浏览器君.

在 GET 的时候添加 header 有很多方法, 下面介绍两种方法.

第一种方法比较简便直接, 但是不好扩展功能, 代码如下:
  1. import urllib.request
  2. url = 'http://www.baidu.com/'
  3. req = urllib.request.Request(url, headers = {
  4.     'Connection': 'Keep-Alive',
  5.     'Accept': 'text/html, application/xhtml+xml, */*',
  6.     'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
  7.     'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
  8. })
  9. oper = urllib.request.urlopen(req)
  10. data = oper.read()
  11. print(data.decode())        
复制代码



第二种方法使用了 build_opener 这个方法, 用来自定义 opener, 这种方法的好处是可以方便的拓展功能, 例如下面的代码就拓展了自动处理 Cookies 的功能.
  1. import urllib.request
  2. import http.cookiejar
  3. # head: dict of header
  4. def makeMyOpener(head = {
  5.     'Connection': 'Keep-Alive',
  6.     'Accept': 'text/html, application/xhtml+xml, */*',
  7.     'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
  8.     'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
  9. }):
  10.     cj = http.cookiejar.CookieJar()
  11.     opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
  12.     header = []
  13.     for key, value in head.items():
  14.         elem = (key, value)
  15.         header.append(elem)
  16.     opener.addheaders = header
  17.     return opener
  18. oper = makeMyOpener()
  19. uop = oper.open('http://www.baidu.com/', timeout = 1000)
  20. data = uop.read()
  21. print(data.decode())
复制代码


上述代码运行后通过 Fiddler 抓到的 GET 报文如下所示:
  1. GET http://www.baidu.com/ HTTP/1.1
  2. Accept-Encoding: identity
  3. Connection: close
  4. Host: www.baidu.com
  5. User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
  6. Accept: text/html, application/xhtml+xml, */*
  7. Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3
复制代码


可见我们在代码里写的东西都添加到请求报文里面了.

保存抓回来的报文

顺便说说文件操作. Python 的文件操作还是相当方便的. 我们可以讲抓回来的数据 data 以二进制形式保存, 也可以经过 decode() 处理成为字符串后以文本形式保存. 改动一下打开文件的方式就能用不同的姿势保存文件了. 下面是参考代码:
  1. def saveFile(data):
  2.     save_path = 'D:\\temp.out'
  3.     f_obj = open(save_path, 'wb') # wb 表示打开方式
  4.     f_obj.write(data)
  5.     f_obj.close()
  6. # 这里省略爬虫代码
  7. # ...
  8. # 爬到的数据放到 dat 变量里
  9. # 将 dat 变量保存到 D 盘下
  10. saveFile(dat)
复制代码


下回我们会用 Python 来爬那些需要登录之后才能看到的信息. 在那之前, 我已经对 Fiddler 稍微熟悉了. 希望一起学习的也提前安装个 Fiddler 玩一下.

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条