初级爬虫第三天

主要内容:

  • 付费IP的使用方式
  • Auth认证
  • cookie登录验证
  • requests模块

 一、付费IP使用方式:

1.1 无论是免费IP还是付费IP,在使用之前,都需要测试一下,如果好使,再去使用IP爬取数据。

1.2 IP池:列表套字典

eg:[{"https": "IP1:端口1"}, {"http": "IP2: 端口2"}, {"https": "IP3: 端口3"}]

1.3 遍历IP池,利用遍历出来的IP创建IP处理器,再利用处理创建发送网络请求的opener对象

1.4 opener.open()中有一个参数timeout=x,即:x秒之后如果程序还没有反应,就算做超时,报超时,x默认为30

1.5 利用异常处理IP值不好用的报错或者超时

代码:

 1 import urllib.request
 2 
 3 爬取百度首页"https://www.baidu.com/"
 4 def proxy_user():
 5     #1.目标网页URL
 6     url = "https://www.baidu.com/"
 7     #2. User-Agent
 8     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"]
 9     request = urllib.request.Request(url)
10     request.add_header("User-Agent", user_agent[0])
11     #3. 代理IP池
12     #3.1 创建代理IP池
13     #IP池结构是:列表套字典
14     proxy_ip_list = [{"HTTP": "58.253.152.23:9999"}, {"HTTP": "112.87.68.242:9999"}, {"HTTP": "60.13.42.99:9999"}]
15     #3.2 遍历IP
16     for choose__proxy_ip in proxy_ip_list:
17         #3.3 利用遍历出来的IP创建IP处理器
18         proxy_ip_handler = urllib.request.ProxyHandler(choose__proxy_ip)
19         #3.4 利用处理器创建opener对象
20         opener = urllib.request.build_opener(proxy_ip_handler)
21         #3.5 发送网络请求
22         #利用异常处理+timeout参数,处理IP失效问题
23         #如果IP使用异常,或者超过timeout设置时间,
24         #则抛出异常,暂停使用当前IP,接着使用下一个IP
25         try:
26             #使用opener.open()发送网络请求,
27             #超时参数timeout设置为10,超过10秒未响应,视为超时
28             response = opener.open(request, timeout = 10)
29         except Exception as e:
30             #如果IP使用异常,或者超时,打印异常信息
31             print(e)
32             
33 
34 proxy_user()

 

查看结果,发现当上一个IP不好用时,程序会自动使用下一个IP

2. 付费IP的两种写法:

2.1 写法1:发送付费的代理IP请求

(1)创建代理IP池

(2)创建handler处理器

(3)创建opener对象

(4)发送网络请求

注意:付费代理IP需要有:1. 购买时的用户名 2. 购买时的密码

代理IP池结构:列表套字典

其中字典结构:{"协议类型": "username: password@IP地址:端口号"}

 1 import urllib.request
 2 
 3 #付费代理IP第一种写法:
 4 def money_proxy_user():
 5     #url = "http://www.baidu.com/"
 6     
 7     #1. IP池
 8     #结构:{"http/https": "username:pwd@IP:端口号"}
 9     money_proxy_list = [{"http": "abc:123@58.253.152.23:9999"}, 
10                         {"http": "abc:123@112.87.68.242:9999"}, 
11                         {"http": "abc:123@60.13.42.99:9999"}]
12     #遍历IP
13     for proxy_ip in money_proxy_list:
14         #2. 创建代理IP处理器handler
15         ProxyHandler = urllib.request.ProxyHandler(proxy_ip)
16         #3. 创建opener对象
17         opener = urllib.request.build_open(ProxyHandler)
18         #4. 发送网络请求
19         response = opener.open(url)                

2.2 付费IP第二种写法:使用密码管理器(推荐)

(1)创建IP池

(2)创建密码管理器

(3)向密码管理器中,添加用户名和密码

(4)创建处理器

(5)创建opener对象

(6)opener对象发送网络请求

 1 import urllib.request
 2 
 3 #付费代理IP第二种写法:
 4 def money_proxy_user():
 5     url = "http://www.baidu.com/"
 6     
 7     #1. 创建IP池
 8     #结构:{"http/https": "IP值:端口号"}
 9     money_proxy_list = [{"http": "58.253.152.23:9999"}, 
10                         {"http": "112.87.68.242:9999"}, 
11                         {"http": "60.13.42.99:9999"}]
12     #遍历IP
13     for proxy_ip in money_proxy_list:
14         #2. 创建密码管理器
15         #密码管理器需要购买IP的用户名和密码
16         user_name = "abc"
17         password = "123"
18         pass_word_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
19         #3. 向密码管理器添加用户名和密码
20         pass_word_manager.add_password(None, proxy_ip, user_name, password)
21         #4. 创建handler处理器
22         money_proxy_handler = urllib.request.ProxyBasicAuthHandler(pass_word_manager)
23         #5. 创建opener对象
24         opener =urllib.request.build_opener(money_proxy_handler)
25         #6. 发送请求
26         response = opener.open(url)
27         

注意:

1. 密码管理器对象,添加用户名和密码的方法:'

add_password(Realm, uri, user_name, password)

第一个参数realm是与远程服务器相关的域信息,一般没人管它都是写None

参数uri:填写代理IP!!!

user_name:付费IP用户名

password:付费IP密码

2. 本方式中,如果程序中提供的代理IP全部都不能使用,程序会使用本地IP

二、Auth认证:

使用范围:

(1)爬取公司内网数据

(2)通过第三方认证的方式(如:微信账号登录),进行爬取

方法:使用密码管理器

代码:

 1 import urllib.request
 2 
 3 def auth_user():
 4     #1. 给出内网账号和密码
 5     user_name = "abc"
 6     pwd = "123"
 7     #2. 内网的URL地址
 8     nei_url = "xxx"
 9     
10     #3. 创建密码管理器
11     pwd_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
12     #4. 向密码管理器中,添加用户名和密码
13     #注意此时,add_password()的第二个参数要访问的目标网页URL地址
14     pwd_manager.add_password(None, nei_url, user_name, pwd)
15     
16     #5. 创建处理器Handler
17     auth_handler = urllib.request.HTTPBasicAuthHandler(pwd_manager)
18     #6. 创建opener对象
19     opener = urllib.request.build_opener(auth_handler)
20     
21     #7. 发送网络请求:
22     response = opener.open(nei_url)

 

2.5:SSL爬虫报错:SSL: CERTIFICATE_VERIFY_FAILED

当使用urllib.request.urlopen()向https网页发送网络请求时,有时会报这个错误:

urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)

解决方法:导入ssl模块和如下代码,即可解决

1 import ssl
2 
3 ssl._create_default_https_context = ssl._create_unverified_context

三、Cookie与登录信息:

目标:爬取药智网的会员中心页面数据

URL:https://www.yaozh.com/member/

目标网页截图:

3.1  第一次爬取:

 1 import urllib.request
 2 import ssl
 3 
 4 #忽略SSL验证
 5  ssl._create_default_https_context = ssl._create_unverified_context
 6 
 7 #1. 目标网页URL
 8 url = "https://www.yaozh.com/member/"
 9 
10 #2. User-Agent
11 #2.1 创建request对象
12 request = urllib.request.Request(url)
13 #2.2 User-Agent池
14 user_agent_headers = ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"]
15 #2.3 向request对象添加User-Agent
16 request.add_header("User-Agent", user_agent_headers[0])
17 
18 #也可以直接在创建request对象时,添加User-Agent
19 #request = urllib.request.Request(url, headers=user_agent_headers[0])
20 
21 
22 #3. 代理IP
23 #3.1 代理IP池
24 proxy_ip = {"https": "60.13.42.101:9999"}
25 #3.2 创建自定义处理器handler
26 proxy_handler = urllib.request.ProxyHandler(proxy_ip)
27 #3.3 创建自定义opener对象
28 opener = urllib.request.build_opener(proxy_handler)
29 
30 
31 #4. 发送网络请求
32 response = opener.open(request)
33 
34 #5. 读取返回的数据
35 data = response.read().decode('utf-8')
36 
37 #6. 数据持久化
38 with open("yaozh01.html", 'w', encoding='utf-8') as f:
39     f.write(data)

得到结果:

结果,个人中心页面未登录

——(1)原因:登录需要账号信息:用户名和密码

但是,爬虫代码中,没有这两个信息

——(2)解决方法:向请求头中,添加cookie

因为,所有的个人信息,包括:账号和密码都保存在cookie中。

一旦用户登录成功,其账号和密码就会自动保存在cookie中。

而cookie位于请求头中。

——(3)所以,我们需要先登录成功一次,获取cookie,然后,将cookie添加到请求头中。这样,以后爬虫代码发送网络请求登录时,就可以自动使用第一次登陆成功后,保存下来的cookie,使用它里面的账号信息。

3.2 方式1:手动获取添加cookie:

(1)手动登录账号,进入个人中心页面

(2)f12,进入network,查看请求头request_headers

(3)如图所示,将cookie后面的所有信息全部复制粘贴,添加进请求头

(4)发送网络请求

 1 import urllib.request
 2 import ssl
 3 
 4 
 5 #爬取药智网会员中心界面
 6 #"https://www.yaozh.com/member/"
 7 
 8 #忽略SSL验证
 9 ssl._create_default_https_context = ssl._create_unverified_context
10 
11 #1. 目标网页URL
12 url = "https://www.yaozh.com/member/"
13 
14 #2. 请求头信息
15 #User-Agent、Cookie
16 #手动填写用户名和密码,进行登录,登陆成功之后,在会员中心页面,f12查看请求头信息,复制User-Agent和Cookie信息
17 user_agent = {"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",
18               "Cookie": "acw_tc=2f624a1c15572983332095835e56ab374f19bbfa04320ed34624c8cb736211; PHPSESSID=db04icmo08qlth57e283e1jug6; Hm_lvt_65968db3ac154c3089d7f9a4cbb98c94=1557298333; MEIQIA_VISIT_ID=1KwMiirKV6lBEDTorlxXFpIQYZ2; MEIQIA_EXTRA_TRACK_ID=1KwMiirgbfupj7bs3kZzgBM0zWb; Hm_lpvt_65968db3ac154c3089d7f9a4cbb98c94=1557298612; yaozh_logintime=1557298624; yaozh_user=743973%09wtf1234; yaozh_userId=743973; db_w_auth=666998%09wtf1234; UtzD_f52b_saltkey=NQ3FQNjM; UtzD_f52b_lastvisit=1557295025; UtzD_f52b_lastact=1557298625%09uc.php%09; UtzD_f52b_auth=760dhxbJO6R21izVhpr2PAlqsjjpHEtuxu9QWpf%2FdzfvGFnBP6V66TEdhcVOWltYjPEmVh4tVSLLQTPKM12K%2BlK55Ls; yaozh_uidhas=1; yaozh_mylogin=1557298627; acw_tc=2f624a1c15572983332095835e56ab374f19bbfa04320ed34624c8cb736211; MEIQIA_VISIT_ID=1KwMiirKV6lBEDTorlxXFpIQYZ2; MEIQIA_EXTRA_TRACK_ID=1KwMiirgbfupj7bs3kZzgBM0zWb"
19               }
20 #2.2 创建request对象,并添加User-Agent
21 request = urllib.request.Request(url, headers=user_agent)
22 
23 
24 #3. 代理IP
25 #3.1 代理IP,IP池
26 proxy_ip = {"https": "115.159.155.60:8118"}
27 #3.2 创建自定义处理器对象handler
28 proxy_handler = urllib.request.ProxyHandler(proxy_ip)
29 #3.3 创建自定义opener对象
30 opener = urllib.request.build_opener(proxy_handler)
31 
32 
33 #4. 发送网络请求,登录
34 response = opener.open(request)
35 #5. 读取返回数据
36 data = response.read().decode('utf-8')
37 
38 #6. 数据持久化
39 with open("yaozhi02.html", "w", encoding='utf-8') as f:
40     f.write(data)

 结果:

可以看到,在本机启动的网页会员中心,这次有了用户名,说明登录成功。

———手动获取cookie的缺点:(1)麻烦;(2)获取的cookie有时效性

3.3 方式2:使用代码自动获取cookie(重点)

目标:自动获取(登陆后的)会员中心页面

难点:获取cookie,即:获取登录所需用户名和密码。由于在登录成功之后,Cookie会被自动保存,所以,要想获取Cookie,先要登录成功。

登录页面login和会员中心页面member是两个不同的页面,所以需要我们现在login页面登录成功,然后拿着cookie,去请求member页面

步骤:

(1)自动登录(但需要自己手动设置用户名和密码),登录成功之后,会自动保存Cookie

(2)代码自动获取Cookie

(3)带着cookie,代码请求会员中心页面,获取会员中心数据

———————————分割线—————————————————————

(1)为了能让程序自动登录,我们需要查看,登录过程中,浏览器都向服务器提交了哪些数据

由于登录过程为:

  1. 浏览器向服务器提交登录数据
  2. 服务器验证数据
  3. 服务器向浏览器发送新的跳转页面的链接
  4. 浏览器按照跳转页面的链接,向服务器重新发送请求

所以,在登录页面,点击“登录”按钮之后,页面会跳转到新的页面。此时浏览器network抓取到的数据,是第4步:浏览器向服务器按照跳转页面URL,向服务器发送请求时,的数据;而不是第1步:浏览器向服务器提交的登录数据。因为谷歌浏览器会只保留最新一次请求的数据,而将之前的请求抹除了。

所以,在f12的network中,点击preserve log按钮,这样浏览器就会保留之前发送过的请求日志。

点击preserve log按钮,在https://www.yaozh.com/login/操作登录,发现浏览器进行登录时,发送的是一个叫做“login”的网络请求。

点击login请求,发现:(1)login发送的是POST请求!!!;(2)Form Data:Form Data为需要发送POST请求时,要发送的参数

 

 1 import urllib.request
 2 import urllib.parse
 3 import http.cookiejar
 4 import ssl
 5 
 6 #忽略SSL验证
 7 ssl._create_default_https_context = ssl._create_unverified_context
 8 
 9 #目标:爬取会员中心网页
10 
11 #1. 会员登录,获取cookie
12 #1.1 登录网页URL
13 login_url = "https://www.yaozh.com/login/"
14 
15 #1.2 请求头信息User-Agent
16 user_agent = {"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 #1.3 构造请求参数
19 #构造POST请求参数,格式必须是字典
20 #发现登录请求中,发送的是POST请求,POST请求有请求参数
21 #POST请求中需要用到的参数:位于浏览器请求头的Form Data中,将其中的数据全部复制下来
22 """
23 username: wtf1234
24 pwd: 123456
25 formhash: 3210139E64
26 backurl: https%3A%2F%2Fwww.yaozh.com%2F
27 """
28 login_request_data = {"username": "wtf1234",
29                       "pwd": "123456",
30                       "formhash": "3210139E64",
31                       "backurl": "https%3A%2F%2Fwww.yaozh.com%2F"}
32 
33 
34 #1.4 转换POST请求参数格式
35 #POST请求中,上传的请求参数必须是2进制格式
36 login_request_data_bytes = urllib.parse.urlencode(login_request_data).encode("utf-8")
37 
38 #1.5 向request对象中,添加URL地址、User-Agent、POST请求参数
39 #get请求中,参数拼接到URL地址中;POST请求中,Request对象里面专门有个data参数,用于接收POST请求参数
40 login_request = urllib.request.Request(login_url, headers=user_agent, data=login_request_data_bytes)
41 
42 #1.6 构造CookieJar对象——用于保存管理cookie
43 my_cookiejar = http.cookiejar.CookieJar()
44 
45 #1.7 构造自定义的可以添加cookie的处理器handler
46 #handler处理器的参数是构造的cookiejar对象
47 #因为urlopen()中不能添加cookie,所以我们需要找一个能添加cookie的处理器,然后再创建opener,再发送网络请求
48 cookie_handler = urllib.request.HTTPCookieProcessor(my_cookiejar)
49 
50 #1.8 使用处理器handler对象,构造自定义opener对象
51 opener = urllib.request.build_opener(cookie_handler)
52 
53 #1.9 使用opener对象,发送网络请求
54 #此时的login_request,既包含请求头信息,又包含请求参数
55 #此时,如果请求发送成功,则cookiejar对象会自动将cookie信息保存到opener对象中
56 opener.open(login_request)      #由于我们这里只是为了登录成功,获取cookie,所以不需要response对象接收返回数据
57 
58 
59 #2. 使用cookie,访问会员中心网页
60 #2.1 会员中心URL
61 member_url = "https://www.yaozh.com/member/"
62 
63 #2.2 构造请求头,添加User-Agent信息
64 user_agent2 = {"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"}
65 member_request = urllib.request.Request(member_url, headers=user_agent2)
66 
67 #2.3 拿着刚才获得的cookie,发送网络请求
68 #由于opener对象中已经保存有cookie信息,所以直接用opener对象发送网络请求即可
69 response = opener.open(member_request)
70 
71 #3. 读取数据
72 data = response.read().decode("utf-8")
73 
74 #4. 持久化
75 with open("yaozhi_day03.html", 'w', encoding='utf-8') as f:
76     f.write(data)

 爬取结果:

注:目前为止学过的反爬机制:

(1)User-Agent:模拟真实用户

同一个浏览器,短时间内频繁访问,反爬

(2)IP地址:

同一个IP地址,短时间内频繁访问,反爬

(3)账号:

同一个账号,短时间内在不同地点(使用不同IP地址)访问,反爬

三、初学requests模块:

理论:

(1)requests模块为第三方模块

(2)使用方法:import requests     注意末尾多一个s

(3)优点:

  • 简单易用
  • URL会自动转译
  • python2、python3的方法名字一样
  • 有官方中文文档
 1 import requests
 2 
 3 #爬取百度首页"https://www.baidu.com/"
 4 
 5 #1. 目标网页URL
 6 url = "https://www.baidu.com/"
 7 
 8 #2. 发送get请求
 9 response = requests.get(url)
10 #返回的response为状态码
11 
12 #3.解析数据
13 #3.1 方式1:使用content属性解析,返回的是2进制数据
14 data = response.content.decode('utf-8')
15 
16 #3.2 方式2:使用text属性解析,返回的是字符串格式数据
17 str_data = response.text
18 #但是不建议,使用此种方式解析数据,因为text内部,将2进制数据转换为字符串格式,靠猜。

 

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/tommyngx/p/10830178.html