前言
网络爬虫(Web Spider。又被称为网页蜘蛛。网络机器人,又称为网页追逐者),是一种依照一定的规则,自己主动的抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁,自己主动索引。模拟程序或者蠕虫。假设把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。
网络蜘蛛是通过网页的链接地址来寻找网页的。从站点某一个页面(一般是首页)开始,读取网页的内容。找到在网页中的其他链接地址。然后通过这些链接地址寻找下一个网页。这样一直循环下去,直到把这个站点全部的网页都抓取完为止。假设把整个互联网当成一个站点。那么网络蜘蛛就能够用这个原理把互联网上全部的网页都抓取下来。这样看来,网络爬虫就是一个爬行程序,一个抓取网页的程序。
简单地说,网络爬虫的基本任务就是抓取网页内容。
1.数据分析和采集
此爬虫教程中使用的Python版本统一为Python3.X的版本
1.1数据分析
爬取网页信息可以使用很多的技术:
1.获取网页信息: urllib \ urllib3 \ requests
1 2
| requests 为第三方库, 需要安装爱才能使用 pip install requests
|
2.解析网页信息: beautifulsoup4(bs4) \ re \ xpath \ lxml
1 2 3
| bs4 为第三方的库, 需要安装才能使用 pip install beautifulsoup4 使用的时候 from bs4 import BeautifulSoup 这样导入
|
Python 标准库中自带了 xml 模块,但是性能不够好,而且缺乏一些人性化的 API,相比之下,第三方库 lxml 是用 Cython 实现的,而且增加了很多实用的功能。
1 2 3 4 5
| 安装lxml,在新版本中无法使用from lxml import etree
pip install lxml 并不推荐这样去安装lxml
推荐安装的方法:访问网站(https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml)下载lxml的安装whl文件,然后进行安装。
|
在这里下载的是lxml-4.2.1-cp36-cp36m-win_amd64.whl,安装命令如下
1
| pip install lxml-4.2.1-cp36-cp36m-win_amd64.whl
|
截图:

3.动态数据解析
通用: selenium(自动化测试框架)
1.2数据采集
1.存储 : mysql \ redis \ mongodb \ sqlalchemy
2.序列化 : json
3.调度器 : 进程 \ 线程 \ 协程
2.请求头分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| # 浏览器告诉服务器可以接收的文本类型, */*表示任何类型都可以接收 Accept: text/html, */*;q=0.8
# 浏览器告诉服务器, 数据可以压缩, 页面可以解压数据然后进行渲染, 做爬虫的时候, 最好不要写该参数 Accpet-Encoding: gzip, deflate
# 语言类型 Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
# 保持连接 Connection: keep-alive
# 会话 Cookie: Hm_lvt_3bfcc098e0da26d58c321ba579b04b2f=1527581188,1528137133
# 域名 Host: www.cdtopspeed.com
Upgrade-Insecure-Requests: 1
# 用户代理, 使得服务器能够识别请求是通过浏览器请求过来的,其中包含浏览器的名称/版本等信息 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
|
其中在爬虫中最重要的就是User-Agent:在下面urllib的使用中就会详细的解释User-Agent的使用
3.urllib的使用
使用urllib来获取百度首页的源码
1 2 3 4
| import urllib.request
r = urllib.request.urlopen('http://www.baidu.com') print(r.read().decode('utf-8'))
|
按照我们的想法来说,输出的结果应该是百度首页的源码才对,但是输出却不对(多请求几次,就会出现如下的结果),如下结果:
1 2 3 4 5 6 7 8 9 10
| <html> <head> <script> location.replace(location.href.replace("https://","http://")); </script> </head> <body> <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript> </body> </html>
|
以上的结果并不是我们想要的,我们可以来查看一下为什么会出现这种问题的原因。我们可以想到刚才说的,请求头中的最重要的参数User-Agent参数,该参数是用来告诉服务器,请求的url是来源于哪儿的,是来源于浏览器还是来源于其他地方的。如果是来源于非浏览器的会就不会返回源码信息给你的,直接拦截掉你的请求
分析以上代码中,默认提交的请求头中的User-Agent到底传递了什么值:

接下来,就是优化以上的代码,实现目的就是告诉服务器我们这个请求是来源于浏览器的。
1 2 3 4 5 6 7 8
| header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.181 Safari/537.36' } res = urllib.request.Request('http://www.baidu.com', headers=header) # 读取url的页面源码 r = urllib.request.urlopen(res) # decode解码, encode编码 print(r.read().decode('utf-8'))
|
按照这样去解析,就可以获取到百度的首页源代码了,展示部门代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <html> <head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta content="always" name="referrer"> <meta name="theme-color" content="#2932e1"> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> <link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" /> <link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">
<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 id="css_index" index="index" type="text/css">html,body{height:100%} html{overflow-y:auto} body{font:12px arial;text-align:;background:#fff} body,p,form,ul,li{margin:0;padding:0;list-style:none} body,form,#fm{position:relative} td{text-align:left} img{border:0} a{color:#00c} a:active{color:#f60} input{border:0;padding:0} #wrapper{position:relative;_position:;min-height:100%} #head{padding-bottom:100px;text-align:center;*z-index:1}
...忽略.... ...忽略.... ...忽略....
</body> </html>
|
4. ssl认证
什么是 SSL 证书?
SSL 证书就是遵守 SSL 安全套接层协议的服务器数字证书。
而 SSL 安全协议最初是由美国网景 Netscape Communication 公司设计开发的,全称为:安全套接层协议 (Secure Sockets Layer) , 它指定了在应用程序协议 ( 如 HTTP 、 Telnet 、 FTP) 和 TCP/IP 之间提供数据安全性分层的机制,它是在传输通信协议 (TCP/IP) 上实现的一种安全协议,采用公开密钥技术,它为 TCP/IP 连接提供数据加密、服务器认证、消息完整性以及可选的客户机认证。由于此协议很好地解决了互联网明文传输的不安全问题,很快得到了业界的支持,并已经成为国际标准。
SSL 证书由浏览器中“受信任的根证书颁发机构”在验证服务器身份后颁发,具有网站身份验证和加密传输双重功能。
如果能使用 https:// 来访问某个网站,就表示此网站是部署了SSL证书。一般来讲,如果此网站部署了SSL证书,则在需要加密的页面会自动从 http:// 变为 https:// ,如果没有变,你认为此页面应该加密,您也可以尝试直接手动在浏览器地址栏的http后面加上一个英文字母“ s ”后回车,如果能正常访问并出现安全锁,则表明此网站实际上是部署了SSL证书,只是此页面没有做 https:// 链接;如果不能访问,则表明此网站没有部署 SSL证书。
案例:
访问加密的12306的网站
如果不忽略ssl的安全认证的话,网页的源码会提示ssl认证问题,需要提供ssl认证。我们在做爬虫的时候,自动设置忽略掉ssl认证即可。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| import ssl import urllib.request
def main(): url = 'http://www.12306.cn/mormhweb/' # 忽略未经审核的ssl认证 context = ssl._create_unverified_context() res = urllib.request.urlopen(url, context=context) print(res.read().decode('utf-8')) if__name__ == '__main__': main()
|
5. 分析百度的搜索
当我们通过百度搜索引擎去搜索python语言的时候,可以发现百度搜索的url中有很多无用的参数,过滤掉无用的参数,最后的请求url可以展示为,如下的信息:
1
| https://www.baidu.com/s?wd=python%E8%AF%AD%E8%A8%80
|
5.1 使用urllib进行中文的编码和解码
1 2 3 4 5 6 7 8 9 10 11
| from urllib import parse
# 编码 enstr = parse.urlencode({'kd': '千峰'}) # 打印的结果为 kd=%E5%8D%83%E5%B3%B0 print(enstr)
# 解码 destr = parse.unquote(enstr) # 解码的结果为 kd=千峰 print(destr)
|
1.2 简单案例–百度搜索(search_spider03.py)
自定义百度的搜索url,获取页面源码。以下案例中,我搜索易烊千玺,查看一下搜索e的结果页面如何。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import urllib.request from urllib import parse
def baidu_api(search): url = 'http://www.baidu.com/?' + search header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' } res = urllib.request.Resquest(url=url, headers=header) r = urllib.request.urlopen(res) print(r.read().decode('utf-8')) if__name__ == '__main__': search = input('请输入搜索的数据: ') wd = parse.urlencode({'wd': search}) baidu_api(wd)
|
1.3 智联岗位爬取(zhilian_spider.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import re import urllib.request from urllib import parse
def get_zhilian_html(url): """ 获取智联上招聘信息 获取职位的个数 <span class="search_yx_tj"> 共<em>1473</em>个职位满足条件 </span> """ header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36' } req = urllib.request.Request(url, headers=header) res = urllib.request.urlopen(req) # 正则匹配, 查询的结果为职位的个数 def get_job_num(html): result = re.findall('<em>(\d+)</em>, html') if result: return result[0] else: return 0 if __name__ == '__main__': # 获取从客户端接收到的参数 city = input('请输入所搜城市: ') job = input('请输入搜索岗位: ') # 将输入的参数进行解码, 输入参数Python和成都, 输出结果为:j1=%E6%88%90%E9%83%BD&kw=python search = parse.urlencode({'j1': city, 'kw': job}) # urllib进行解析网站的url url = 'https://sou.zhaopin.com/jobs/searchresult.ashx?%s' % search' html = get_zhilian_html(url) # 进行解析地址 result = get_job_num(html) print('城市: %s 岗位: %s 需求量: %s' % (city, job, result))
|
调试:搜索成都的python岗位的职位个数
