介绍了2种反爬的方式:
- 请求头
- 代理IP
一、反爬手段1——向请求头中添加User-Agent:
请求头、响应头:
1.响应头:response_header
响应头response_header,可以通过response对象.headers,获取得到。
response.headers,得到的是响应头信息
1 def load(): 2 # 1.目标网页URL地址 3 URL = "http://www.baidu.com/" 4 5 # 2.发送网络请求: 6 # 返回response对象,使用response对象接收服务器返回的数据 7 response = urllib.request.urlopen(URL) 8 9 # 得到响应头信息 10 print(response.headers) 11 12 load()
结果为:
1 Bdpagetype: 1 2 Bdqid: 0xbfd0e4790001890b 3 Cache-Control: private 4 Content-Type: text/html 5 Cxy_all: baidu+739fcb9dd92b830634cd2f957c8e6f67 6 Date: Fri, 03 May 2019 15:30:05 GMT 7 Expires: Fri, 03 May 2019 15:29:21 GMT 8 P3p: CP=" OTI DSP COR IVA OUR IND COM " 9 Server: BWS/1.1 10 Set-Cookie: BAIDUID=2D1BE12D094679CAE43187C509B76E5D:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com 11 Set-Cookie: BIDUPSID=2D1BE12D094679CAE43187C509B76E5D; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com 12 Set-Cookie: PSTM=1556897405; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com 13 Set-Cookie: delPer=0; path=/; domain=.baidu.com 14 Set-Cookie: BDSVRTM=0; path=/ 15 Set-Cookie: BD_HOME=0; path=/ 16 Set-Cookie: H_PS_PSSID=28884_1454_21091_28724_28963_28837_28584; path=/; domain=.baidu.com 17 Vary: Accept-Encoding 18 X-Ua-Compatible: IE=Edge,chrome=1 19 Connection: close 20 Transfer-Encoding: chunked
和浏览器中f12,network中的Response Headers显示的信息对比,基本一致
2.请求头:request_header(重点)
User-Agent是在模拟真实用户发送网络请求
(1)目的:我们要向请求头里面,添加User-Agent信息,这样就可以干掉一部分的反爬手段。
(2)request = urllib.request.Request(目标网页URL地址)
——创建request对象
要想获取请求头request_header,我们需要先创建request对象,然后通过request对象获取请求头。
注意:Request()首字母必须大写
(3)request.headers,就可以得到请求头的信息。
(4)request.add_header('User_Agent', 'xxx')
——向请求头中添加‘User-Agent’信息
使用爬虫,最开始时,请求头request_header中是空的,为了模拟真实用户,需要向请求头request_header中添加信息;必须先创建request对象之后,再向request_header中添加请求头信息。
xxx就是冒号(:)后面的那些
(5)response = urllib.request.urlopen(request)
发送网络请求,这个方法的参数,既可以是URL地址,也可以是request对象。
(6)request.get_header('User-agent')
——获取请求头信息的第二种方式
注意:
a. 这里的参数是'User-agent',只有U大写,A小写;
request.add_header()中,"User-Agent",U和A都大写。
b. request.get_header(),这个方法只能得到请求头的一部分信息
如:request.get_header('User-agent')只会得到User-Agent信息
而request.headers,得到的是请求头的全部信息
(7)request.get_full_url()
可以得到完整的URL
(8)添加User-Agent信息,爬取百度首页
1 import urllib.request 2 import urllib.parse 3 4 #爬取百度首页https://www.baidu.com/ 5 def load(): 6 #1.目标网页URL 7 URL = "https://www.baidu.com/" 8 9 #2.向请求头中添加User-Agent信息 10 #2.1创建request对象,参数为目标网页的URL 11 request = urllib.request.Request(URL) 12 13 #打印最开始时请求头的User-Agent 14 print(request.get_header('User-agent')) 15 #2.2向请求头中添加User-Agent信息 16 request.add_headers('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36') 17 18 #再次打印请求头的User-Agent 19 print(request.get_header('User-agent')) 20 21 #3.发送网络请求,response接收返回数据 22 #参数填写添加User-Agent信息之后的request对象 23 response = urllib.request.urlopen(request) 24 25 load()
结果:
可以看到,一开始时,User-Agent的信息为None,添加之后,为我们添加的信息
注意:发送网络请求的代码,urllib.request.urlopen(request)参数填写request对象,而非URL;
如果填URL,则发送请求的请求头没有添加我们添加的User-Agent信息,还是为空None。
1.5 使用多个User-Agent:
(1)由于爬虫会在极短的时间内(一秒钟),访问服务器很多次(几百次)。所以,如果只使用一个User-Agent,很容易被服务器识别为爬虫。
(2)反爬手段2.5:使用多个User-Agent
- 百度搜索:User-Agent大全
- 使用fake User-Agent(包含250个User-Agent)
- User-Agent池(推荐)
——这样,每次发送网络请求的浏览器信息和个人信息都不一样,就可以干掉反爬了
(3)思路:设置一个User-Agent的列表,每次从中随机选取一个User-Agent
(4)代码:
import urllib.request import urllib.parse import random #爬取百度首页https://www.baidu.com/ def load(): #1.目标网页URL URL = "https://www.baidu.com/" #2.向请求头中添加User-Agent信息 #2.1 设置User-Agent池: user_agent_list = ['Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60', 'Opera/8.0 (Windows NT 5.1; U; en)', 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0', 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10;', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60', 'Opera/8.0 (Windows NT 5.1; U; en)', 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0', 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36', ] #2.2 从User-Agent池中随机选择一个User-Agent choose_user_agent = random.choice(user_agent_list) #2.2创建request对象,参数为目标网页的URL request = urllib.request.Request(URL) #打印最开始时请求头的User-Agent print(request.get_header('User-agent')) #2.2向请求头中添加User-Agent信息 request.add_headers('User-Agent', choose_user_agent) #再次打印请求头的User-Agent print(request.get_header('User-agent')) #3.发送网络请求,response接收返回数据 #参数填写添加User-Agent信息之后的request对象 response = urllib.request.urlopen(request) load()
二、反爬手段2——代理IP:
理论:
(1)IP分为免费IP和付费IP:
1.1 免费IP:时效性差,错误率高
1.2 付费IP:时效性强,错误率低,但是也有失效的IP
(2)IP的三种叫法:
2.1 透明IP:对方知道我自己的真实IP
2.2 匿名IP:对方不知道我自己的真实IP,但是知道我使用了代理IP
2.3 高匿名IP:对方不知道我自己的真实IP,也不知道我使用了代理IP
注:由图可以发现,代理IP分为HTTP和HTTPS,可以根据自己的需求,找自己要的类型IP
(3)IP分为免费IP写法和付费IP写法
(4)发送网络请求,需要使用我们自己添加的代理IP。看上面的爬虫代码,可以发现:在发送网络请求之前,只涉及到两个东西,一个是request对象、另一个是urllib.request.urlopen()方法。
查看request和urlopen()
通过查看request对象和urlopen()方法源码,发现这两个对象,都没有提供加入代理IP的位置。
所以,我们应该在哪里加入,我们自己想要伪装的代理IP呢???
查看urlopen()方法代码
发现:该方法的本质是创建了一个opener对象,返回的是opener.open()
而opener对象,又是通过build_opener()一个handler处理器对象得来的
所以说,如果能在handler对象中加入我们要伪装的代理IP,然后用该对象创建opener对象,再调用open()方法,就可以达到我们的目的:伪装使用代理IP向服务器发送网络请求。
总结一下:
- urlopen()和request对象都没有添加IP的方法
- urlopen()的底层本质上是:先创建handler对象,然后创建opener对象,再用opener.open()的方法发送网络请求,爬取数据。
- 我们需要创建一个能够添加代理IP的handler处理器——proxyhandler,然后利用它创建opener对象,最后发送请求。
代码:
import urllib.request import urllib.parse import string import random # 使用添加的User-Agent和代理IP,爬取搜狗搜索的首页 def load(): # 1.目标网页URL: URL = 'https://www.sogou.com/' # 2.向请求头添加User-Agent # 2.1创建request对象 request = urllib.request.Request(URL) # 2.2设置User-Agent池 User_Agent_List = [ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60', 'Opera/8.0 (Windows NT 5.1; U; en)', 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0', 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10;', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60', 'Opera/8.0 (Windows NT 5.1; U; en)', 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0', 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36', ] # 2.3每次请求随机选择一个User-Agent choose_User_Agent = random.choice(User_Agent_List) # 2.4向请求头信息中,添加User-Agent request.add_header('User-Agent', choose_User_Agent) # 3.添加代理IP # 3.1设置代理IP proxy_ip = {'https': '116.52.13.90:808'} # 3.2创建handler处理器对象 proxy_handler = urllib.request.ProxyHandler(proxy_ip) # 3.3创建opener对象(因为真正发送网络请求的是opener而非handler) opener = urllib.request.build_opener(proxy_handler) # 3.4调用open方法,发送网络请求 response = opener.open(request) # 4.发送网络请求,使用response对象接收数据 #因为3.4中已经做了 # 5.读取response对象里面的数据,转码为字符串格式 str_data = response.read().decode('utf-8') # 6.保存数据 with open('sougou.com02.html', 'w', encoding='utf-8') as f: f.write(str_data) load()
注意:
(1)代理IP的设置格式:
1.1 使用字典放置
1.2 键key:相应的代理IP的类型(http或者https)
1.3 值value:代理IP:端口号
1.4 键http/https;值IP地址+端口号,均使用字符串格式
eg:
proxy = {'http': "115.223.69.54:8010", "https": "116.209.52.248:9999"}
(2)opener.open()中的参数,既可以是目标网页的URL也可以是request对象。这里由于,我们要使用添加的User-Agent,所以参数用request对象。