所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地。 在Python中有很多库可以用来抓取网页,先学习urllib2
。
urllib2模块直接导入就可以用,在python3中urllib2被改为urllib.request
开始爬虫需要准备的一些工具
(1)下载Fiddeler抓包工具,百度直接下载安装就可以(抓包)
(2)下载chrome浏览器代理插件 Proxy-SwitchyOmega(代理)
(3)下载chrome浏览器插件XPath(解析HTML)
(4)工具网站:
http://www.json.cn/ (json解析网站)
http://tool.chinaz.com/tools/urlencode.aspx (url编码解码网站)
先写个简单的爬虫百度页面
urlopen
# _*_ coding:utf-8 _*_
import urllib2
#向指定的url地址发送请求,并返回服务器响应的类文件对象
response = urllib2.urlopen('http://www.baidu.com/')
#服务器返回的类文件对象支持python文件对象的操作方法
#read()方法就是读取文件里的全部内容,返回字符串
html = response.read()
print html
urllib2默认的User-Agent是Python-urllib/2.7,容易被检查到是爬虫,所以我们要构造一个请求对象,要用到request方法。
模拟浏览器访问
浏览器访问时通过抓包工具获得的headers信息如下:
GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh,zh-CN;q=0.8,ar;q=0.6,zh-TW;q=0.4
Cookie: BAIDUID=AE4D1DA6B2D6689BB8C557B3436893E3:FG=1; BIDUPSID=AE4D1DA6B2D6689BB8C557B3436893E3; PSTM=1501466227; BD_CK_SAM=1; PSINO=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BD_HOME=0; H_PS_PSSID=1420_25548_21080_20929; BD_UPN=12314353
我们要设置User-Agent模仿浏览器去访问数据
# _*_ coding:utf-8 _*_
import urllib2
# User-Agent是爬虫与反爬虫的第一步
ua_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
# 通过urllib2.Request()方法构造一个请求对象
request = urllib2.Request('http://www.baidu.com/',headers=ua_headers)
#向指定的url地址发送请求,并返回服务器响应的类文件对象
response = urllib2.urlopen(request)
# 服务器返回的类文件对象支持python文件对象的操作方法
# read()方法就是读取文件里的全部内容,返回字符串
html = response.read()
print html
Request总共三个参数,除了必须要有url参数,还有下面两个:
-
data(默认空):是伴随 url 提交的数据(比如要post的数据),同时 HTTP 请求将从 "GET"方式 改为 "POST"方式。
-
headers(默认空):是一个字典,包含了需要发送的HTTP报头的键值对。
response的常用方法
# _*_ coding:utf-8 _*_
import urllib2
# User-Agent是爬虫与反爬虫的第一步
ua_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
# 通过urllib2.Request()方法构造一个请求对象
request = urllib2.Request('http://www.baidu.com/',headers=ua_headers)
#向指定的url地址发送请求,并返回服务器响应的类文件对象
response = urllib2.urlopen(request)
# 服务器返回的类文件对象支持python文件对象的操作方法
# read()方法就是读取文件里的全部内容,返回字符串
html = response.read()
# 返回HTTP的响应吗,成功返回200,4服务器页面出错,5服务器问题
print response.getcode() #200
# 返回数据的实际url,防止重定向
print response.geturl() #https://www.baidu.com/
# 返回服务器响应的HTTP报头
print response.info()
# print html
随机选择一个Use-Agent
为了防止封IP,先生成一个user-agent列表,然后从中随机选择一个
# _*_ coding:utf-8 _*_
import urllib2
import random
url = 'http:/www.baidu.com/'
# 可以试User-Agent列表,也可以是代理列表
ua_list = ["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
# 在User-Agent列表中随机选择一个User-Agent
user_agent = random.choice(ua_list)
# 构造一个请求
request = urllib2.Request(url)
# add_header()方法添加/修改一个HTTP报头
request.add_header('User-Agent',user_agent)
#get_header()获取一个已有的HTTP报头的值,注意只能第一个字母大写,后面的要小写
print request.get_header('User-agent')
urllib和urllib2的主要区别
urllib和urllib2都是接受URL请求的相关模块,但是提供了不同的功能,最显著的区别如下:
(1)urllib仅可以接受URL,不能创建,设置headers的request类实例;
(2)但是urllib提供urlencode()方法用来GET查询字符串的产生,而urllib2则没有(这是urllib和urllib2经常一起使用的主要原因)
(3)编码工作使用urllib的urlencode()函数,帮我们讲key:value这样的键值对转换成‘key=value’这样的字符串,解码工作可以使用urllib的unquote()
urllib.encode()的使用
urlencode() 里面必须是字典类型
# _*_ coding:utf-8 _*_
import urllib
dic = {'derek':'编码'}
print urllib.urlencode(dic) #derek=%E7%BC%96%E7%A0%81
m = urllib.urlencode(dic)
print urllib.unquote(m) #derek=编码
一般HTTP请求提交数据,需要编码成 URL编码格式,然后做为url的一部分,或者作为参数传到Request对象中。
GET请求一般用于我们向服务器获取数据,比如说,我们用百度搜索知乎
:https://www.baidu.com/s?wd=知乎
发现GET https://www.baidu.com/s?wd=%E7%9F%A5%E4%B9%8E,后面是一个长长的字符串,urldecode后发现就是知乎
用urllib.urlencode()进行转码,然后组合url
# _*_ coding:utf-8 _*_
import urllib,urllib2
url = 'http://www.baidu.com/s'
headers = {'UserAgent':'Mozilla'}
keyword = raw_input('请输入关键字:')
wd = urllib.urlencode({'wd':keyword})
fullurl = url + '?' + wd
print fullurl
request = urllib2.Request(fullurl,headers=headers)
response = urllib2.urlopen(request)
print response.read()
然后输入关键字,爬取下对应的内容
爬取贴吧内容
先了解贴吧url组成:
每个贴吧url都是以'https://tieba.baidu.com/f?'开头,然后是关键字 kw=‘’贴吧名字‘’,再后面是 &pn=页数 (pn=0第一页,pn=50第二页,依次类推)
1.先写一个main,提示用户输入要爬取的贴吧名,并用urllib.urlencode()进行转码,然后组合url
2.接下来,写一个百度贴吧爬虫接口tiebaSpider(),需要传递3个参数给这个接口, 一个是main里组合的url地址,以及起始页码和终止页码,表示要爬取页码的范围。
3.前面写出一个爬取一个网页的代码。然后,将它封装成一个小函数loadPage(),供我们使用。
4.将爬取到的每页的信息存储在本地磁盘上,我们可以简单写一个存储文件的接口writePage()
# _*_ coding:utf-8 _*_
import urllib,urllib2
def loadPage(url,filename):
#根据url发送请求,获取服务器响应文件
print '正在下载' + filename
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
request = urllib2.Request(url,headers = headers)
content = urllib2.urlopen(request).read()
return content
def writePage(html,filename):
#将html内容写入到本地
print '正在保存' + filename
with open(unicode(filename,'utf-8'),'w') as f:
f.write(html)
print '_' * 30
def tiebaSpider(url,beginPage,endPage):
#贴吧爬虫调度器,负责组合处理每个页面的url
for page in range(beginPage,endPage + 1):
pn = (page - 1) * 50
filename = '第' + str(page) + '页.html'
fullurl = url + '&pn=' + str(pn)
# print fullurl
html = loadPage(fullurl,filename)
writePage(html,filename)
if __name__ == '__main__':
kw = raw_input('请输入贴吧名:')
beginPage = int(raw_input('请输入起始页:'))
endPage = int(raw_input('请输入结束页:'))
url = 'https://tieba.baidu.com/f?'
key = urllib.urlencode({'kw':kw})
fullurl = url + key
tiebaSpider(fullurl,beginPage,endPage)
通过输入想要搜索的贴吧名字,爬取内容并保存到本地
获取Ajax方式加载的数据
爬虫最需要关注的不是页面信息,而是页面信息的数据来源
Ajax方式加载的页面,数据来源一定是JSON,直接对AJAX地址进行post或get,拿到JSON,就是拿到了网页数据,
(1)先通过浏览器访问豆瓣电影排行榜
https://movie.douban.com/typerank?type_name=%E5%89%A7%E6%83%85&type=11&interval_id=100:90&action=
只要response里面有 JSON数据,我们就可以找到服务器的数据来源
分析发现变动的是start value和limit value, type,interval_id,action,固定不变,这三个url中已经包含了,所以formdata只用传start和limit
import urllib
import urllib2
url = 'https://movie.douban.com/typerank?type_name=%E5%89%A7%E6%83%85&type=11&interval_id=100:90&action='
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
# start和limit可以自己随便设置
formdata = {'start':'20','limit':'100'}
data = urllib.urlencode(formdata)
request = urllib2.Request(url,data = data,headers=headers)
response = urllib2.urlopen(request)
print response.read()