(爬虫)urllib库

一、爬虫简介

  什么是爬虫?通俗来讲爬虫就是爬取网页数据的程序。

  要了解爬虫,还需要了解HTTP协议和HTTPS协议:HTTP协议是超文本传输协议,是一种发布和接收HTML页面的传输协议;HTTPS协议则是HTTP协议的安全版,在HTTP下加入了SSL层,SSL(安全套接层)主要是用于web的安全传输协议,在传输层对网络连接进行加密,保证在网络上数据传输的安全。

  要进行爬虫,必须知道浏览器发送HTTP请求的过程是什么样的:1、首先用户在浏览器输入一个URL进行访问请求,浏览器会向服务器发送Request请求(请求主要有GET和POST两种方法),去获取服务器上的数据(也就是HTML文件),服务器或返回文件对象发送给浏览器。2、然后浏览器分析HTML文件,发现其中引用了很多其他的文件,比如Images、css、js文件,根据这些文件的地址再次发送请求去获取这些数据,当所有的文件都下载成功后,浏览器会根据HTML的语法结构,将网页进行显示。

  HTTP的请求方法:

  1. get  请求指定的页面数据,返回数据主体
  2. head  类似于get方法,只不过返回的响应中没有具体的内容,用于获取报头信息
  3. post  向服务器提交数据处理请求,比如表单提交或者是文件上传,该方法可能会导致新的资源的建立和已有资源的修改
  4. put  从客户端向服务器传送的数据取代指定的文档的内容
  5. delete    请求服务器删除指定的数据
  6. connect    在HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
  7. options    允许客户端查看服务器的性能
  8. trace    回显服务器收到的请求,主要用于测试或者诊断

  HTTP常见的响应状态码:

  • 1xx    信息

    1、100    Continue

      服务器仅接受到部分的请求,如果服务器没有拒绝该请求,客户端应该继续发送其余的请求。

    2、101    Switching Protocols

      服务器将遵从客户端的请求转到到另外一种协议。

  • 2xx    成功

    1、200    OK

      请求成功(后面是对GET和POST请求的应答文档)

    2、201    Created

      请求被创建完成,同时新的资源被创建

    3、202    Accepted

      处理的请求已被接受,但是处理还未完成

    4、203    Non-authoritative Information

      文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝

    5、204    No Content

      没有新文档,浏览器应该继续显示原来的文档

    6、205    Reset Content

      没有新文档,浏览器应该重置它所显示的内容,用来强制浏览器清除表单输入的内容

    7、206    Partial Content

      客户端发送了一个带有Range头的GET请求,服务器完成了它

  • 3xx    重定向

    1、300    Multiple Choices

      多重选择,有一个链接列表,用户可以选择某个链接到达目的地,最多允许五个地址

    2、301    Moved Permanently

      请求的页面已经转移到新的url上

    3、302    Moved Temporarily

      请求的页面被临时转移到新的url上

    4、303    See Other

      请求的页面可在别的url下被找到

    5、304    Not Modified

      未按照预期去修改文档

    6、305    Use Proxy

      客户请求的文档应该通过Location头所指明的代理服务器提取

    7、306    Unused

      此代码用于前一个版本,目前已不再使用,但是代码依然被保留

  • 4xx    客户端错误

    1、400    Bad Request

      服务器未能理解请求

    2、401    Unauthorized

      被请求的页面需要用户名和密码

    3、402    Payment Required

      此代码目前无法使用

    4、403    Forbidden

      请求的页面禁止访问

    5、404    Not Found

      服务器无法找到请求的页面

    6、405    Method Not Allowed

      请求中指定的方法不被允许

  • 5xx    服务器错误

    1、500    Internal Server Error

      请求未完成,服务器遇到了未知的错误

    2、501    Not Implemented

      请求未完成,服务器不支持所请求的功能

    3、502    Bad Gateway

      请求未完成,服务器从上游服务器收到了一个无效的响应

    4、503    Service Unavailable

      请求未完成,服务器临时过载或者当机

    5、504    Gateway Timeout

      网关超时

    6、505    HTTP Version Not Supported

      服务器不支持请求中指明的HTTP协议版本

二、urllib库介绍

urllib库是python中一个最基本的网络请求库,它可以向指定的服务器发送网络请求,并保存服务器返回的数据。

三、urllib库常用的函数

1、request.urlopen(url, data=None)

  • url:请求的url
  • data:请求的数据,如果设置了这个值,就变成了post请求
  • 该方法返回一个HTTPResponse对象,该对象有read(size)、readline()、readlines()、getcode()等方法

使用urlopen请求函数请求百度的页面:

1 from urllib import request
2 
3 resp = request.urlopen("http://www.baidu.com/")
4 print(resp.read())

2、request.urlretrieve(url, file_path)

  • url:请求的url
  • file_path:数据保存的文件位置
  • 将请求的页面(资源)保存到本地

请求百度的页面,并将请求的HTML页面保存到本地:

1 from urllib import request
2 
3 resp = request.urlretrieve("http://www.baidu.com/", "baidu.html")

3、parse.urlencode(params)

  • params:需要编码的数据
  • 在浏览器发送请求的url都是经过编码的,所以在爬虫程序中需要对这些数据进行编码
1 from urllib import parse
2 
3 url = "https://www.baidu.com/s?"
4 params = {"wd": "孔明"}
5 qs = parse.urlencode(params)
6 url = url + qs
7 print(url)

4、parse.parse_qs(qs)

  • qs:编码后的数据
  • 将编码后的数据进行解码
1 from urllib import parse
2 
3 params = {"name": "孔明", "age": 52, "greet": "hello world"}
4 qs = parse.urlencode(params)
5 print(qs)
6 result = parse.parse_qs(qs)
7 print(result)

5、parse.urlparse(url)

  • 对url进行解析,解析后的参数如下运行结果。
  • 还有一个方法与该方法的作用一致urlsplit,只不过这个方法比urlparse方法少了params参数。
1 from urllib import parse
2 
3 url = "http://www.baidu.com/s?wd=python&username=wj#1"
4 qs = parse.urlparse(url)
5 print(qs)

运行结果如下:
ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='', query='wd=python&username=wj', fragment='1')

6、request.Request类

  • 如果想要伪装是爬虫程序在请求页面,就需要增加一些请求头信息,将爬虫程序伪装的更加像浏览器发送请求,这是就需要用到Request类来实现增加请求头信息。
1 from urllib import request
2 
3 url = "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput="
4 headers = {
5     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
6 }
7 req = request.Request(url, headers=headers)
8 resp = request.urlopen(req)
9 print(resp.read())

三、爬虫小案例

1、爬取拉勾网的职位信息

  • 拉钩网的职位信息是通过异步加载上来的,所以直接请求职位的url在HTML页面中是没有职位信息的,所以需要先找到请求职位数据的url,在网络请求中有一个叫positionAjax.json的文件,点开这个文件的Request URL就是请求职位信息的url,使用这个url来发起请求
  • 拉钩还将请求的GET方法改成了POST方法,所以还需要将方法改成POST方法,提交data数据,提交的数据也在positionAjax.json文件中的Form data中,将这些数据进行提交,而且还要对这些数据进行urlencode编码,然后encode编码成bytes。
 1 from urllib import request
 2 from urllib import parse
 3 
 4 url = "https://www.lagou.com/jobs/positionAjax.json?city=%E5%8C%97%E4%BA%AC&needAddtionalResult=false"
 5 headers = {
 6     'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
 7     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
 8 }
 9 data = {
10     'first': 'true',
11     'pn': 1,
12     'kd': 'python'
13 }
14 
15 req = request.Request(url, headers=headers, data=parse.urlencode(data).encode('utf-8'), method='POST')
16 resp = request.urlopen(req)
17 print(resp.read().decode('utf-8'))

四、ProxyHandler处理器(代理设置)

  • 很多网站会检测某一段时间内某个IP的访问次数,如果访问次数过多,服务器会禁止这个IP访问,所以可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被封,还可以换另一个IP来继续爬取。
  • http://httpbin.org/ip这个网站可以查看当前访问的IP地址。
  • 在urllib库中,可以通过ProxyHandler处理器来设置使用代理服务器,如下例:
1 from urllib import request
2 
3 url = 'http://httpbin.org/ip'
4 
5 handler = request.ProxyHandler({'http': '115.223.193.24:9000'})
6 opener = request.build_opener(handler)
7 resp = opener.open(url)
8 print(resp.read())

 五、cookiejar和HTTPCookieProcessor模拟登陆

1、cookie原理

  • 在网站中,http请求是无状态的,也就是说第一次和服务器连接并登陆成功后,第二次请求服务器服务器依然不知道当前请求的是哪个用户。
  • cookie的出现解决了这个问题,在第一次登陆后服务器返回一些cookie信息给浏览器,然后浏览器保存到本地,在用户发起第二次请求时,会将上次保存的cookie信息携带发送给服务器,这时服务器就能判断当前请求的是哪个用户了。

2、cookie的格式

  Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

  • NAME:cookie的名字
  • VALUE:cookie的值
  • Expires:cookie的过期时间
  • Path:cookie作用的路径
  • Domain:cookie作用的域名
  • SECURE:是否只在http协议下起作用

3、通过cookie模拟登陆

  通过cookie登陆有两种方法,第一种是比较笨的方法,直接拿到cookie的值放到header中去发起请求,这里以人人网的登录为例:

 1 from urllib import request
 2 
 3 # 请求大鹏主页url
 4 url = 'http://www.renren.com/880151247/profile'
 5 headers = {
 6     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36',
 7     'Cookie': 'anonymid=jnzs4b8t-zbhqll; _r01_=1; ln_uact=13993601652; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; jebe_key=60f2d634-5d83-45f3-b930-3f1422c2a256%7Cb939033e6ecb601b13da2fa06ef0385f%7C1543636386271%7C1%7C1543636386784; depovince=BJ; JSESSIONID=abcbMP1G0kvXfgE9C6aEw; ick_login=d5e719ea-5ab2-43b5-abb2-de404e8c2915; jebecookies=b94d14bf-81e6-4595-aa51-ab932f554a25|||||; _de=FD8333DB14E9BE28EF9216E27A2AD80C; p=6fed63e36db2313d64fdd4e6136df3cd0; first_login_flag=1; t=04b39f2437865dd6085372c2fcabb2c80; societyguester=04b39f2437865dd6085372c2fcabb2c80; id=967643640; xnsid=7f13361d; ver=7.0; loginfrom=null; wp_fold=0; jebe_key=60f2d634-5d83-45f3-b930-3f1422c2a256%7Cb939033e6ecb601b13da2fa06ef0385f%7C1543636386271%7C1%7C1544056994153'
 8 }
 9 
10 req = request.Request(url=url, headers=headers)
11 resp = request.urlopen(req)
12 with open('renren.html', 'w', encoding='utf-8') as f:
13     f.write(resp.read().decode('utf-8'))

  这种方式不建议去使用,也没人去这样写,我们可以使用通过cookiejar和HTTPCookieProcessor来实现模拟登陆:

 1 from urllib import request
 2 from urllib import parse
 3 from http.cookiejar import CookieJar
 4 
 5 
 6 login_url = 'http://www.renren.com/PLogin.do'
 7 dapeng_url = 'http://www.renren.com/880151247/profile'
 8 headers = {
 9     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36',
10 }
11 data = {
12     'email': '17319045463',
13     'password': 'xxxxxxx'
14 }
15 
16 cookiejar = CookieJar()
17 handler = request.HTTPCookieProcessor(cookiejar)
18 opener = request.build_opener(handler)
19 
20 # 模拟登陆
21 req = request.Request(login_url, data=parse.urlencode(data).encode('utf-8'), headers=headers)
22 opener.open(req)
23 req = request.Request(dapeng_url, headers=headers)
24 resp = opener.open(req)
25 with open('renren.html', 'w', encoding='utf-8') as f:
26     f.write(resp.read().decode('utf-8'))

  现在将这个功能封装成函数的形式:

 1 from urllib import request
 2 from urllib import parse
 3 from http.cookiejar import CookieJar
 4 
 5 
 6 headers = {
 7     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36',
 8 }
 9 
10 def get_opener():
11     cookiejar = CookieJar()
12     handler = request.HTTPCookieProcessor(cookiejar)
13     opener = request.build_opener(handler)
14     return opener
15 
16 def login_renren(opener):
17     login_url = 'http://www.renren.com/PLogin.do'
18     data = {
19         'email': '17319045463',
20         'password': 'xxxxx'
21     }
22 
23     req = request.Request(login_url, data=parse.urlencode(data).encode('utf-8'), headers=headers)
24     opener.open(req)
25 
26 def visit_dapeng(opener):
27     dapeng_url = 'http://www.renren.com/880151247/profile'
28     req = request.Request(dapeng_url, headers=headers)
29     resp = opener.open(req)
30     with open('renren.html', 'w', encoding='utf-8') as f:
31         f.write(resp.read().decode('utf-8'))
32 
33 if __name__ == '__main__':
34     opener = get_opener()
35     login_renren(opener)
36     visit_dapeng(opener)

4、cookie信息的保存与加载

4.1 cookie的保存

  cookie信息可以保存在文件中,使用MozillaCookieJar可以将cookie信息保存在文件中,CookieJar是将cookie信息保存在内存中,想用哪种方法视情况而定:

1 cookiejar = MozillaCookieJar('cookie.txt')
2 handler = request.HTTPCookieProcessor(cookiejar)
3 opener = request.build_opener(handler)
4 req = opener.open('http://www.baidu.com/')
5 
6 cookiejar.save(ignore_discard=True)

4.2 cookie信息的加载

  可以将cookie信息从文件中加载出来:

1 cookiejar = MozillaCookieJar('cookie.txt')
2 cookiejar.load(ignore_discard=True)
3 handler = request.HTTPCookieProcessor(cookiejar)
4 opener = request.build_opener(handler)
5 req = opener.open('http://www.baidu.com/')
6 
7 for cookie in cookiejar:
8     print(cookie)
posted @ 2018-12-06 14:51  Sweltering  阅读(549)  评论(0编辑  收藏  举报