代理
自定义Opener
我们之前一直都在使用的urlopen,它是一个特殊的opener,是模块帮我们创建好的。但是我们可以不用他的,我们可以重新写一个
自定义Opener会有更高级的用法
import urllib.request
# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求
http_handler = urllib.request.HTTPHandler()
# 构建一个HTTPHandler 处理器对象,支持处理HTTPS请求
# http_handler = urllib.request.HTTPSHandler()
# 调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
opener = urllib.request.build_opener(http_handler)
# 构建 Request请求
request = urllib.request.Request("http://www.baidu.com/")
# 调用自定义opener对象的open()方法,发送request请求
response = opener.open(request)
# 获取服务器响应内容
print (response.read().decode())
代理设置
-
-
代理的作用:
-
1.突破自身IP访问限制,访问一些平时不能访问的站点。
-
2.访问一些单位或团体内部资源:比如使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
-
3.提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度。
-
4.隐藏真实IP:上网者也可以通过这种方法隐藏自己的IP,免受攻击。对于爬虫来说,我们用代理就是为了隐藏自身IP,防止自身的IP被封锁。
-
-
根据协议划分
-
FTP代理服务器**:主要用于访问FTP服务器,一般有上传、下载的功能以及缓存的功能,端口号一般为21,2121等。**
-
HTTP代理服务器**:主要用于访问网页,一般有内容过滤和缓存的功能,端口号一般为80、8080、3128等**
-
SSL/TLS代理:主要能用于访问加密的网站,一般有SSL或者TLS加密**
-
SOCKS代理:只是单纯的用于传输数据包,不关心具体的协议用法,速度快、有缓存功能,端口号一般为1080
-
-
根据匿名内容划分
-
高度匿名代理:会将数据包原封不动的转发,在服务器看来就好像真的是一个普通的用户短在访问,而记录的IP就是代理服务器的IP
-
普通匿名代理:会在数据包上做一些改动,服务端上有可能发现这个是代理服务器,也有一定的几率追查到客户端的真实IP.
-
透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP,这种代理除了用缓存技术提高浏览器速度。能用内容过滤提高安全性之外,并没有其他作用。
-
使用代理IP这是爬虫/反爬虫的第二大招,通常也是最好用的。
-
-
-
代理网站
- 西刺免费代理IP
- 快代理免费代理
from urllib import request,error
#构建支持代理的handler
proxy = {
'http':'61.138.33.20:808',
'https':'120.69.82.110:44693',
}
proxy_handler = request.ProxyHandler(
proxies=proxy
)
#付费代理的话
#构建一个私密代理Handler,需要加上私密代理账户的用户名和密码
# authproxy = {
# "http" :"username:password@61.135.217.7:80"
#}
# authproxy_handler=urllib.request.ProxyHandler(
# proxies=authproxy
#)
#根据proxy_handler实例化一个opener对象
opener = request.build_opener(proxy_handler)
url = 'http://www.baidu.com/'
# 使用https://httpbin.org/get接口验证使用了代理
# url = 'https://httpbin.org/get'
try:
response = opener.open(url,timeout=5)
print(response.status)
except error.HTTPError as err:
print(err.reason)
except error.URLError as err:
print(err.reason)
# 1. 如果按照上面代码,只有使用opener.open()方法发送
请求才使用自定义的代理,而urlopen()则不使用自定义代理。
response = opener.open(request)
# 2. 将自定义的opener设置为全局的opener,之后所有的,不管是
opener.open()还是urlopen() 发送请求,都将使用自定义代理。
# request.install_opener(opener)
# response = urlopen(request)
案例
西刺爬爬爬
这个用的json保存的数据,(列表转json用dumps),
import urllib.request
import re
import ssl
import json
ssl._create_default_https_context = ssl._create_unverified_context
class XiCiSpied():
def __init__(self):
self.url = 'https://www.xicidaili.com/nn/'
self.headers = {
'User_Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
}
self.proxy_list = []
def send_request(self,url):
request = urllib.request.Request(headers=self.headers,url=url)
response = urllib.request.urlopen(request)
if response.status == 200:
return response
def save_content(self):
#用json去保存
with open('proxy.json','wa') as f:
#wa为了防止后面的内容覆盖到前面的
f.write(json.dumps(self.proxy_list))#把列表转json
def parse_content(self,response):
content = response.read().decode('utf8')
pattern = re.compile(r'<td>(\d.*?\.\d.*?\.\d.*>\.\d.*?)</td>.*?<td>(\d.*?)</td>.*?<td>(^HT.*?)</td>',re.S)
result = re.findall(pattern,content)
#print(result)
for proxy in result:
#proxy是元组
file_proxy = {}
file_proxy['type'] = proxy[2]
file_proxy['proxy'] = proxy[0] + ':'+proxy[1]
self.proxy_list.append(file_proxy)
#类型应该是
#[{'type':.'...','proxy':'.....'},{},{}....]
def strat(self):
for i in range(1,3):
full_url = self.url + str(i)
response = self.send_request(full_url)
if response:
self.parse_content(response)
self.save_content()
if __name__ == '__main__':
xc = XiCiSpied()
xc.strat()
西刺已经爬下来了,但是用的时候应该怎么用呢(json转列表用loads)
import urllib.request
import re
import ssl
import json
import random
ssl._create_default_https_context = ssl._create_unverified_context
class XiCiSpied():
def __init__(self):
self.url = 'https://www.xicidaili.com/nn/'
self.headers = {
'User_Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
}
#先从文件中把数据读出来
f = open('proxy.json','r')
#self.proxy_list = f.read()#这个返回的是json字符串,我们为了方便,把json再转化为列表
self.proxy_list = json.loads(f.read())#用列表展示出来
def send_request(self, url):
#每次发送请求都换一个ip
proxy = random.choice(self.proxy_list)#每次随机选择列表里的一个字典
#取出来的数据就是{'',''}
#拼一个代理请求
proxy_user = {
proxy['type']:proxy['proxy']
#http :域名+端口
#取出来的形式就是这种
}
#构造好了代理,就可以发送请求了
#第一步创建一个代理的处理器,ProxyHandler
ProxyHandler = urllib.request.ProxyHandler(
proxies=proxy_user
)
#第二步,根据proxyhandler实例化一个opener对象
opener = urllib.request.build_opener(ProxyHandler)
#然后就可以创建request,发送请求了
request = urllib.request.Request(headers=self.headers, url=url)
response = opener.open(request)#用我自己写的代理去爬
if response.status == 200:
return response
def save_content(self):
# 用json去保存
with open('proxy.json', 'wa') as f:
# wa为了防止后面的内容覆盖到前面的
f.write(json.dumps(self.proxy_list)) # 把列表转json
def strat(self):
for i in range(1, 3):
full_url = self.url + str(i)
response = self.send_request(full_url)
print(response.read().decode('utf8'))#把爬下来的数据转为pycharm中的语言
self.save_content()
if __name__ == '__main__':
xc = XiCiSpied()
xc.strat()
urllib模拟登录
找cookie,它的作用,最直接的一个就是检测用户是否登录
from urllib.request import urlopen, Request
url = 'https://www.douban.com/people/215936188/'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
'Cookie':'ll="118109"; bid=MBXAroZsxpg; __gads=ID=807be06ae84daac4:T=1586955001:S=ALNI_MbNx5wdtDXSr1YcYP6kc0Hzrm-lEQ; douban-fav-remind=1; __yadk_uid=m6SxzsoQjJAgI1dKZbMAafkN1UB9e3i1; push_noty_num=0; push_doumail_num=0; __utmv=30149280.21593; douban-profile-remind=1; gr_user_id=e29cb43e-c8cd-406c-8cfa-0f9f40721306; _vwo_uuid_v2=DA157A200A3523F60609A6064D6D6AC7E|f4c9a8fcb2b43a2a794ccbbddbf6c0e6; ct=y; __utmc=30149280; viewed="35026481_35013916_34787187_34429244_5907931"; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1592043440%2C%22https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DenlCus0VTvqF-g0PNsBGwVH7QXvKHuaoW9A8DGTyzAgp6LIRXKks4G2DBDFgjnfJ%26wd%3D%26eqid%3D9b37fe5600100819000000045ee4a7ad%22%5D; _pk_ses.100001.8cb4=*; __utma=30149280.1178102369.1587959982.1592021478.1592043442.12; __utmz=30149280.1592043442.12.11.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmt=1; dbcl2="215936188:WVVGPPVRVy4"; ck=eEss; ap_v=0,6.0; _pk_id.100001.8cb4=3c5cdcff0213d411.1587105741.12.1592043607.1592022425.; __utmb=30149280.5.10.1592043442',
}
ret = Request(url, headers=headers)
res = urlopen(ret)
with open('douban.html','wb') as f:
f.write(res.read())
但是遇到这种的,每次都去登录然后获取cookie有点麻烦
模拟登录,不用去登录再去复制cookie了
from urllib.request import urlopen, Request
from http.cookiejar import CookieJar
import urllib.parse
login_url = 'https://www.wanandroid.com/user/login'
form_data = {
'username':'liuand',
'password':'l200011280028..',
}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
form_data = urllib.parse.urlencode(form_data).encode('utf8')#编码
cookiejar = CookieJar()
#创建一个处理cookie 的 handler
httpcookieProcessor = urllib.request.HTTPCookieProcessor(cookiejar)
#通过build_opener()来构建opener
opener = urllib.request.build_opener(httpcookieProcessor)
#创建一个request
request = Request(login_url, headers=headers)
#发起请求
response = opener.open(request,data=form_data)
# with open('douban.html','wb') as f:
# f.write(response.read())
print(response.read().decode('utf8'))
#然后爬收藏页
url = 'https://www.wanandroid.com/lg/collect'
response = opener.open(url)
with open('wanandroid.html','wb') as f:
f.write(response.read())
print(response.read)
模拟登录的核心代码and详细解释
import http.cookiejar as cookiejar
from urllib import parse,request
#1.构造一个CookieJar对象实例来保存cookie
cookie = cookiejar.CookieJar()
# 2.使用HTTPCookieProcessor()创建cookie处理器对象,
# 参数为CookieJar()对象
cookie_handler = request.HTTPCookieProcessor(cookie)
#3.通过build_opener()来构建opener
opener = request.build_opener(cookie_handler)
#4.addheaders接受一个列表,里面每一个元素都是一个headers信息的元组
#opener将会附带header信息
opener.addheaders = [
('User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0'),
]
#5.需要登录账号和密码
data = {
'source': 'index_nav',
'form_email': '18518753265',
'form_password': 'ljh123456',
}
#6. 通过urlencode()转码
postdata = parse.urlencode(data).encode('utf-8')
#7. 构建Request请求对象,包含需要发送的用户名和密码
request = request.Request("https://www.douban.com/accounts/login", data = postdata)
# 8. 通过opener发送这个请求,并获取登录后的Cookie值,
opener.open(request)
# 9. opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
response = opener.open("https://www.douban.com/people/175417123/")
#这里为了测试不添加cookie时访问改界面的效果
#headers = {
# 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 #Firefox/59.0',
#}
# request = request.Request('https://www.douban.com/people/175417123/',headers=headers)
# response = request.urlopen(request)
# 10. 打印响应内容
#打印结果查看是否访问成功
print(response.code)
html = response.read().decode('utf-8')
# print(html)
with open('douban_login.html','w') as f:
f.write(html)
药智网案例
from http.cookiejar import CookieJar
import urllib.request
import re
import ssl
import json
import urllib.parse
ssl._create_default_https_context = ssl._create_unverified_context
class YZSpider():
def __init__(self):
self.login_url = 'https://www.yaozh.com/login/'
self.member_url = 'https://www.yaozh.com/member/'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
self.cookiejar = CookieJar()
#然后再创建一个处理cookie的handler
self.cookie_handler = urllib.request.HTTPCookieProcessor(self.cookiejar)
# 通过build_opener()来构建opener
self.opener = urllib.request.build_opener(self.cookie_handler)
#所有的data这些参数都是需要用urlencode编码的
self.form_data = urllib.parse.urlencode({
'username':'liuand',
'pwd':'l200011280028..',
'formhash': 'B790FFD297',
'backurl': 'https % 3A % 2F % 2Fwww.yaozh.com % 2F'
}).encode('utf8')
def send_request(self):
request = urllib.request.Request(headers=self.headers,data=self.form_data,url=self.login_url)
response = self.opener.open(request)
if response.status == 200:
print('已经登录了')
request = urllib.request.Request(self.member_url,headers=self.headers,data=self.form_data)
response = self.opener.open(request)
if response.status == 200:
print('获取会员页成功')
self.save_content(response)
def save_content(self,reponse):
with open('yaozhi.html','wb') as f:
f.write(reponse.read())
def paser_content(self):
pass
if __name__ == '__main__':
yz = YZSpider()
yz.send_request()