1. urllib库
urllib库是 Python 中一个最基本的网络请求库。可以摸拟法览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据。
2. urlopen函数:
在 Python3的 urllib库中,所有和网络请求相关的方法,都被集到 urllib.request模块下面了,以先来看下urlopen函数基本的使用:
from urllib import request
'''
get获取方式
'''
resp=request.urlopen('http://www.baidu.com') # resp得到响应
# print(resp.read()) # read()将响应当中的数据读取出来
# print(resp.read(5))
# print(resp.readline()) # readline()只读取一行
# print(resp.readlines())
print(resp.getcode()) # 200 返回http状态码
'''
1.read(site):用于从文件读取指定的字节数,如果site未给定或为负则读取所有。
2.readline():每次读取一行内容
3.readlines():读取整个文件所有行,保存在一个列表(list)变量中
4,getcode():返回http状态码
'''
实际上,使用浏览器访问百度,右键查看源代码。你会发现,跟我们刚才打印出来的数据是一模一样的。也就是说,上面的三行代码就已经帮我们把百度的首页的全部代码爬下来了。一个基本的url请求对应的python代码真的非常简单。
以下对urlopen函数的进行详细讲解:
1. url:请求的url。
2. data :请求的data ,如果设置了这个值,那么将变成post 请求。
3.返回值:返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象。有read(size) . readline . readlines以及getcode等方法。
3. urlretrieve函数
retrieve:检索 parse:解析
这个函数可以方便的将网页上的一个文件保存到本地。以下代码可以非常方便的将百度的首页下载到本地:
from urllib import request
request.urlretrieve('http://www.baidu.com', 'baidu.html') # 下载百度网页
# 前面参数是url,后面是保存的路径以及文件名
request.urlretrieve('https://img2.baidu.com/it/u=2348224141,235129573&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500','林俊杰.jpg')
# 网络上下载林俊杰图片
'''
urlretrieve() 方法可以方便的将网页上的一个文件下载并保存到本地
文件类型可以是网页的html文件、图片、视频等媒体文件
函数原型:urlretrieve(url, filename=None, reporthook=None, data=None)
参数 url 指定了要下载的文件的url
参数 finename 指定了保存本地路径(如果参数未指定,urllib会生成一个临时文件保存数据。)
'''
4. urlencode函数& parse_qs函数
from urllib import parse # 对于编码和解码是放在这一个模块中的,用的时候需要导入
urlencode函数:
用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动的给我们进行编码。而如果使用代码发送请求,那么就必须手动的进行编码,这时候就应该使用urlencode函数来实现。urlencode可以把字典数据转换为 URL编码的数据。示例代码如下:
parse_qs函数:
可以将经过编码后的url参数进行解码
from urllib import request # request是存放网络请求相关的
from urllib import parse # 对于编码解码是放在另一个模块中的
# urlencode函数的用法:进行编码
params = {'name': '张三', 'age': 18, 'greet': 'hello world'}
result = parse.urlencode(params) # 将字符串进行编码
print(result)
# 编码结果: name=%E5%BC%A0%E4%B8%89&age=18&greet=hello+world
# hello world 中间的空格使用加号进行区分
url = 'http://www.baidu.com/s'
# 百度上搜索刘德华网址:https://www.baidu.com/s**?**ie=UTF-8&wd=%E5%88%98%E5%BE%B7%E5%8D%8E
params = {"wd": "刘德华"} # 拼接中文应该使用中文编码后的结果
qs = parse.urlencode(params) # params是字典类型
print(qs) # 结果:wd=%E5%88%98%E5%BE%B7%E5%8D%8E
url = url + "?" + qs # 拼接
print(url) # 结果:http://www.baidu.com/s?wd=%E5%88%98%E5%BE%B7%E5%8D%8E
resp=request.urlopen(url)
print(resp.read()) # 读取百度上刘德华html页面全部内容
# parse_qs函数的用法:进行解码
# 先进行编码
params = {'name': '张三', 'age': 18, 'greet': 'hello world'} # 字典类型
qs = parse.urlencode(params)
# 再进行解码
result=parse.parse_qs(qs)
print(result) # {'name': ['张三'], 'age': ['18'], 'greet': ['hello world']}
5.urlparse函数&urlsplit函数
url的组成成分:
http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
1、传输协议(scheme):http
2、主机名/域名(host):www.aspxfans.com 服务器(www)+域名(aspxfans.com)
3、端口号(port):8080
5、路径(path):/news/
6、文件名:index.asp
7、查询字符串(query-string):boardID=5&ID=24618&page=1
8、片段(可省略):name
在浏览器中请求一个url,浏览器会对这个url进行一个编码。出英文字母,数字和部分符号外,其余的全部使用百分号+十六进制值进行编码
有时候拿到一个url,**想要对这个url中的各个组成部分进行分割**,那么这时候就可以使用urlparse或者是urlsplit来进行分割。示例代码如下:
from urllib import parse
'''
urlparse()和urlsplit()的区别:
urlparse()函数比urlsplit()函数基本上是一模一样的。唯一不一样的地方是,urlsplit()的结果中多了一个params属性,而urlparse()没有这个属性。比如有一个url为 'http://www.baidu.com/s;hello?wd=python&username=abc#1' ,那么urlparse可以获取到‘hello’,而urlsplit不可以获取到。
'url'中的‘params’也用得比较少
'''
url = 'http://www.baidu.com/s?wd=python&username=abc#1' # 随便给的例子
# result1 = parse.urlparse(url) # 拿到url当中的每一部分
result2 = parse.urlsplit(url) # 拿到url当中的每一部分 写法合适,可以直接使用这种写法
#print(result1)
# 结果:ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='', query='wd=python&username=abc', fragment='1')
'''
print('scheme:', result1.scheme) # ctrl+d表示复制一份
print('netloc:', result1.netloc)
print('path:', result1.path)
print('query:', result1.query)
print('fragment:', result1.fragment)
上述运行结果:
scheme: http
netloc: www.baidu.com
path: /s
query: wd=python&username=abc
fragment: 1
'''
print(result2)
# 结果:SplitResult(scheme='http', netloc='www.baidu.com', path='/s', query='wd=python&username=abc', fragment='1')
7. request.Request类
如果想要在请求的时候增加一些请求头,那么就必须使用request.Request类来实现。比如要增加一个User-Agent,示列代码如下:
from urllib import request
# url = 'https://www.lagou.com/wn/jobs?labelWords=&fromSearch=true&suginput=&kd=python'
url="https://movie.douban.com/top250?start="
'''
这里是get方式
'''
# resp=request.urlopen(url)
# print(resp.read().decode("utf-8"))
# 拉勾网具有反爬虫,返回的是一串乱码,只有定义headers让网站认为这不是爬虫程序,进行伪装
# 使用前先观察这个网站的请求方式是get还是post方式
'''
post方式/网站识别出为爬虫程序
'''
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36"
} # 是我们所要改动的值
# 创建请求对象(包装请求)-Request
req = request.Request(url, headers=headers) # 与get方式相比就多了这一行
# 发请求,获取响应对象-urlopen
resp = request.urlopen(req)
# 读取内容read
print(resp.read().decode('utf-8'))
'''
url = 'https://www.lagou.com/wn/jobs?labelWords=&fromSearch=true&suginput=&kd=python'
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36"
# 当出现请求太频繁,请稍后再访问,表示网站还能识别是爬虫做的,还要进行伪装,伪装的像一点
“Referer”: ”https://www.lagou.com/“
}
data={
'first':'true',
'pn':1,
'kd'='python'
}
# data数据需要urlencode才能传进 request.Request里面去。通过encode方式转换为byte类型
req = request.Request(url, headers=headers,data=parse.urlencod(data).encode('utf-8'),method='POST')
# 如果网站还能识别是爬虫,不能返回数据,证明伪装性不高,还要进行高度伪装。加上data,heders里面加上refer, request.Request里加上method
resp = request.urlopen(req)
print(resp.read().decode('utf-8'))
# decode('utf-8')是将byte类型解码成Unicode类型
'''
8. ProxyHandler处理器(代理设置)
很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。(简单来说就是利用别人的ip进行爬取数据)
urllib中通过ProxyHandler来设置使用代理服务器,下面代码说明如何使用自定义opener来使用代理:
(http://httpbin.org/ip:这个网站可以查看自己的ip信息)
from urllib import request
# 没有使用代理的
'''
url='http://httpbin.org/ip' # 该网站可以查看没有使用代理时自己的ip地址
resp=request.urlopen(url) # 返回一个响应
print(resp.read()) # 结果:b'{\n "origin": "39.*.*.*"\n}\n'
'''
# 使用代理的
url = 'http://httpbin.org/ip'
# 1.使用ProxyHeader,传入代理构建一个handler
handler = request.ProxyHandler({"http": "120.220.220.95:8085"})
# 这个代理是一个字典,字典的key依赖于代理服务器能够接收的类型,一般是“http”或者“https”,值是“ip:port”
# 2.使用上面创建的handler构建一个opener
opener = request.build_opener(handler)
# 3.使用opener去发送一个请求
resp = opener.open(url)
print(resp.read()) # 结果:b'{\n "origin": "120.220.220.95"\n}\n',ip地址变了,让别人的ip代理了
常用的代理有:
西刺免费代理IP: http://www.xicidali.com/
快代理: http://www.kuaidaili.com/
代理云:http://www.dailiyun.com/
使用http://httpbin.org/ip可以查看没有使用代理时自己的ip地址
'''
总结ProxyHeaderch处理器(代理):
1、代理的原理:在请求目的网站之前,先请求代理服务器,然后让代理服务器去请求目的网站,代理服务器拿到目的网站的数据后,再转发给我们的代码。
2.http://httpbin.org/ip:这个网站可以方便的查看http请求的一些参数
3.在代码中使用代理:
1.使用“urllib.request.ProxyHandler”,传入一个代理,这个代理是一个字典,字典的key依赖于代理服务器能够接收的类型,一般是“http”
或者“https”,值是“ip:port”
2.使用上一步创建的“handler”,以及“request.build_opener”创建一个“opener”对象
3.使用上一步创建的“opener”,调用“open”函数,发起请求
示例代码如上----使用代理的:
'''
9. 什么是cookie:
在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据〈cookie〉给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的 cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
(在以后的开发中,网站的开发80~90%都是使用cookie来实现,在以后写爬虫,需要爬取一些需要登录才能获得的数据,那就必须要和这个cookie打交道)
cookie的格式:
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH; Domain=DOMAIN_NAME; SECURE
10. 使用cookielib库和HTTPCookieProcessor模拟登录:
Cookie是指网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。
这里以人人网为例。人人网中,要访问某个人的主页,必须先登录才能访问(必须处于一种登录状态才能访问),登录说白了就是要有cookie信息。那么如果我们想要用代码的方式访问,就必须要有正确的cookie信息才能访问。解决方案有两种,第一种是使用浏览器览访问,然后将cookie信息复制下来,放到headers中。示例代码如下:
*(**注意:*大家以后在写爬虫的时候,不管对方的网站做没做反爬虫机制,最好的方式就是把user-Agent这个东西加到请求头上去,这是最安全的)
11.http.dookiejar模块:
该模块主要的类有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。这四个类的作用分别如下:
1.CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。
2.FileCookieJar (flename,delayload=None,policy=None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文伴名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。
3.MozillaCookieJar (filename,delayload=None.,policy=None):从FileCookieJar派生而来,创建与Mozilla浏览器cookies.txt兼容的FileCookieJar实例。(保存在内存当中)
4.LWPCookieJar (filename.delayload=None.,policy=None):从FileCookieJar派生而来,创建与libwww-perl标准的Set-Cookle3文件格式兼容的FileCookieJar实例。
利用http.cockiejar和request.HTTPCookieProcessor登录人人网。相关示例代码如下:
12.cookie信息的加载与保存
# 保存cookie到本地
# 保存cookie到本地,可以使用cookiejar的save方法,并且需要指定一个文件名
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar=MozillaCookieJar('cookie.txt')
handler=request.HTTPCookieProcessor(cookiejar)
opener=request.build_opener(handler)
resp=opener.open('http://www.baidu.com')
cookiejar.save()
# 保存cookie到本地
# 保存cookie到本地,可以使用cookiejar的save方法,并且需要指定一个文件名
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar=MozillaCookieJar('cookie.txt')
cookiejar.load(ignore_discard=True) # 加载cookie。 ignore_discard=True:里面将过期的cookie的信息保存下来
handler=request.HTTPCookieProcessor(cookiejar)
opener=request.build_opener(handler)
resp=opener.open('http://baidu.com')
# resp=opener.open('http://httpbin.org/cookies/set?course=abc')
for cookie in cookiejar:
print(cookie)
# cookiejar.save()
生成cookie.txt文件