1、什么是爬虫和爬虫的基本逻辑
“爬虫”是一种形象的说法。互联网比喻成一张大网,爬虫是一个程序或脚本在这种大网上爬走。碰到虫子(资源),若是所需的资源就获取或下载下来。这个资源通常是网页、文件等等。可以通过该资源里面的url链接,顺藤摸瓜继续爬取这些链接的资源。
你也可以把爬虫当作模拟我们正常上网。打开网页并分析网页的内容获取我们想要的东西。
那么,这里就涉及到http传输协议等相关的知识。
我们通常打开一个网页,基本上都是打开一个Url链接即可。在这个过程当中,实际上发生了很多事情。
打开一个Url链接,浏览器自动向Url链接的服务器发送一个请求(Request),告诉服务器说我需要访问这个Url链接的内容,请返回数据给我。服务器就处理该请求,响应该请求并返回结果给浏览器。
既然爬虫需要模拟该过程。根据http协议,爬虫需要构造一个请求(Request),发到请求到目标服务器(通常是Url链接)。然后等待服务器的响应(Response)。
所有相关的数据都在这个响应结果当中,这个就是爬虫实现的基本逻辑。
2、urllib2实现GET请求
GET和POST是请求中最常见的两种方式。(一共有6种)
GET方式是通过Url链接的方式传输相关的参数或数据。一般打开网址是GET方式请求,例如打开百度首页、谷歌首页。
有时候,需要向这个链接传输一些参数。
例如我在百度搜索一个词,发现链接变成 https://www.baidu.com/s?ie=UTF-8&wd=测试
这里有个?问号以及后面一堆数据。问号后面的数据是GET请求的参数,这里一共有两组参数。
1)ie = UTF-8
2)wd = 测试
每组参数用&符号链接。在参数中,等号前面的是参数名;等号后面的是参数值。
例如第2组参数的含义是百度搜索关键字为“测试”。第1组参数是设置返回ie浏览器的编码格式,可有可无,作为说明加入进来。
那么,我使用urllib2模拟百度搜索代码如下:
#coding:utf-8
import urllib, urllib2
#前半部分的链接(注意是http,不是https)
url_pre = ‘http://www.baidu.com/s’
#GET参数
params = {}
params[‘wd’] = u’测试’.encode(‘utf-8’)
url_params = urllib.urlencode(params)
#GET请求完整链接
url = ‘%s?%s’ % (url_pre, url_params)
#打开链接,获取响应
response = urllib2.urlopen(url)
#获取响应的html
html = response.read()
#将html保存到文件
with open(‘test.txt’, ‘w’) as f:
f.write(html)
执行代码,可以看到爬取的内容。
20170331/20170331103813155.png
ps:别被百度骗了,中间都是空行,后面有很还有很多内容。
20170331/20170331104130019.png
上面的链接之所以是http,不是https。因为百度在https做了重定向,重定向到http的链接。
若直接获取https的链接内容是获取不到什么数据。
另外,后面我们会讲解如何处理html的内容,怎么从html中获取我们所需的数据。
好了,先讲解一下代码。
在合并Url链接的时候,使用了urllib库的urlencode方法。该方法是将字典组成x1=a&x2=b的形式。
再看第9行代码,我使用encode方法是为了处理unicode字符串为string字符串。若不做该处理,urlencode方法无法使用。
以上这些都是一些不得不讲的细节,整段代码的核心是第16行和第19行。
第16行是使用urlopen方法打开一个Url链接,发送请求并等待响应;
第19行是从响应(Response)中获取网页的html代码即网页内容。
urlopen方法还有其他参数,格式如下:
urllib2.urlopen(url, data, timeout)
后面两个参数是选填的,data参数是接下来要讲的POST请求所使用到的参数;timeout参数是设置超时时间。
为了避免过长时间未响应,可以使用timeout设置。
urlopen方法还有另外一种格式:
urllib2.urlopen(request, data, timeout)
我比较倾向使用这个方式,逻辑清晰,而且还可以对request做其他设置。上面百度搜索代码可以改成如下:
#coding:utf-8
import urllib, urllib2
#前半部分的链接(注意是http,不是https)
url_pre = ‘http://www.baidu.com/s’
#GET参数
params = {}
params[‘wd’] = u’测试’.encode(‘utf-8’)
url_params = urllib.urlencode(params)
#GET请求完整链接
url = ‘%s?%s’ % (url_pre, url_params)
#构造请求,获取响应
request = urllib2.Request(url)
response = urllib2.urlopen(request)
#获取响应的html
html = response.read()
with open(‘test.txt’, ‘w’) as f:
f.write(html)
3、urllib2实现POST请求
POST请求通常是Form表单提交数据常用的请求方式。
相对GET请求来说,POST请求可以向服务器传递更多的数据。这点是它们之间主要的区别。
通常出现在登录、提交表单、向API接口发送JSON数据这几种情况。
这里需要借助一些辅助工具帮助我们查看浏览器和服务器之间的小动作。
例如在浏览器按F12调试或Fiddler,这些又是一大块知识。大家可以自行搜索和学习。
有关POST请求代码和GET请求差不多。这里没有较好的简单实例,因为很多网址对POST先加密再发送或者加了验证码等等处理。
简单写个表单提交的POST请求代码示例代码,了解一下:
#coding:utf-8
import urllib, urllib2
#构造表单数据,表单数据也是和GET请求一样的形式
values = {}
values[‘username’] = “aaaaaa”
values[‘password’] = “bbbbbb”
data = urllib.urlencode(values)
#构造请求
url = “http://xxxxxxxxxxx”
request = urllib2.Request(url, data)
#响应结果
response = urllib2.urlopen(request)
html = response.read()
print(html)
4、urllib2处理Cookie
http协议还有一个特性:无状态。
因为http协议是处理请求并响应结果,服务器并不知道客户端处于什么状态。例如客户端是否已经登录、客户端访问该Url链接之前打开了什么网页等等。面对这种情况,Cookie就诞生了。
Cookie记录了一些简单的数据。而每个Cookie都有有效期。我们可以标记该客户端当前的状态,例如是否登录、之前查询过什么东西、打开过该网站什么网页等等。
(ps:Cookie是保存在客户端,服务端还有一个差不多的东西:Session,可自行了解。)
urllib2可以获取和记录Cookie。这里需要构造一个opener,不是使用urllib2.urlopen。
urllib2.urlopen也是一个特殊的opener,但我们无法从中获取Cookie。如下代码:
#coding:utf-8
import urllib2
import cookielib
#创建cookie
cookie = cookielib.CookieJar()
handler=urllib2.HTTPCookieProcessor(cookie)
#通过handler来构建自定义opener
opener = urllib2.build_opener(handler)
#此处的open方法同urllib2的urlopen方法
request = urllib2.Request(‘http://www.baidu.com’)
response = opener.open(request)
for item in cookie:
print(‘%s = %s’ % (item.name, item.value))
自定义一个opener,获取Cookie如下:
20170331/20170331115238169.png
我们还可以将Cookie保存到文件,下次需要使用的时候,再读取出来。让服务器误以为我们还在之前的某种状态。
#coding:utf-8
import urllib2
import cookielib
#设置保存cookie的文件路径
filename = ‘cookie.txt’
#使用MozillaCookieJar创建cookie对象
cookie = cookielib.MozillaCookieJar(filename)
handler = urllib2.HTTPCookieProcessor(cookie)
#通过handler来构建opener
opener = urllib2.build_opener(handler)
#创建请求,同urllib2的urlopen
response = opener.open(“http://www.baidu.com”)
cookie.save(ignore_discard=True, ignore_expires=True)
其中,save方法的参数含义如下:
1)ignore_discard是即使cookies将被丢弃,也将其保存下来。
2)ignore_expires是如果在该文件中cookies已经存在,则覆盖写入。
读取Cookie代码如下:
#coding:utf-8
import urllib2
import cookielib
#使用MozillaCookieJar创建cookie对象
cookie = cookielib.MozillaCookieJar()
cookie.load(‘cookie.txt’, ignore_discard=True, ignore_expires=True)
handler = urllib2.HTTPCookieProcessor(cookie)
#通过handler来构建opener
opener = urllib2.build_opener(handler)
#创建请求,同urllib2的urlopen
request = urllib2.Request(“http://www.baidu.com”)
response = opener.open(request)
5、反爬虫设置header
有些服务器为了避免被爬虫,会检查header。header是发送请求的时候,一起发送给服务器的数据。可以通过header得到浏览器的类型,手机端还是电脑端访问,以及从什么地方进入该链接等等。
若发现不是正常浏览器访问,服务器则直接拒绝。
so~ 我们需要进一步模拟浏览器的行为,需要模拟设置header。
#coding:utf-8
import urllib, urllib2
#设置header
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
headers = {‘User-Agent’:user_agent}
#构造Request请求,其中第二个参数是data
url = ‘http://www.server.com/login’
request = urllib2.Request(url, None, headers)
#响应请求
response = urllib2.urlopen(request)
html = response.read()
同样,若你不知道如何设置header,可以通过抓包软件获取,例如Fiddler。
6、解析html
前面说了这么多,都是为了获取网页内容html。既然获取到html之后,我们解析?从中提取我们需要的数据?
我们所获取的html本质是字符串。处理字符串最基本的方法是通过相关的字符串函数,但效率很低,容易出错。
还可以使用正则表达式处理字符串。这部分的知识也是很多,大家可以自行了解。
这里,我想给大家说的处理方式是使用BeautifulSoup。
BeautifulSoup是解析html/xml的库。非Python自带的库,安装如下: