网络请求
urlopen函数用法
urllib库
urllib库是python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据
urlopen函数
在python3的urllib库中,所有和网络请求相关的方法都被集成到urllib.request模块下面了,下面先看下urlopen函数基本使用:
from
urllib
import
request
resp
=
request
.
urlopen
(
'http://www.baidu.com'
)
print
(
resp
.
read
(
)
)
实际上,使用浏览器访问百度,右键查看源代码。就会发现,打印处理的内容就是和请求的内容一摸一样的,也就是说,上面的三行代码已经帮我们将百度首页的内容全部爬下来了
这里对urlopen函数进行详细讲解:
- url:请求的url
- data:请求的data,如果设置了这个值,那么请求将会变成post请求
- 返回值:返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象有read(size)、readline、readlines以及getcode等方法
urlretrieve函数
这个函数可以方便的将网页上的一个文件保存到本地。以下代码可以非常方便的将百度的首页下载到本地
from
urllib
import
request
request
.
urlretrieve
(
'http://www.baidu.com/'
,
'baidu.html'
)
使用这个函数,可以方便我们将图片或者其他的内容下载到本地
urlencode函数
用浏览器发送请求的时候,如果url中包含了中文或者其他特殊符号,那么浏览器会自动给我们进行编码,而如果使用代码发送请求,那么就必须手动进行编码,这时候就应该使用urlencode函数来实现,urlencode可以把字典数据转换为URL编码的数据,示例代码如下:
from
urllib
import
parse
data
=
{
'name'
:
'爬虫基础'
,
'greet'
:
'hello world'
,
'age'
:
100
}
result
=
parse
.
urlencode
(
data
)
print
(
result
)
name
=
%
E7
%
88
%
AC
%
E8
%
99
%
AB
%
E5
%
9F
%
BA
%
E7
%
A1
%
80
&
greet
=
hello
+
world
&
age
=
100
parse_qs函数
可以将经过编码后的url参数进行解码(这个是配合上面urlencode函数配合使用的),示例代码如下:
from
urllib
import
parse
params
=
{
'name'
:
'张三'
,
'age'
:
18
,
'greet'
:
'hello world'
}
qs
=
parse
.
urlencode
(
params
)
print
(
qs
)
result
=
parse
.
parse_qs
(
qs
)
print
(
result
)
name
=
%
E5
%
BC
%
A0
%
E4
%
B8
%
89
&
age
=
18
&
greet
=
hello
+
world
{
'name'
:
[
'张三'
]
,
'age'
:
[
'18'
]
,
'greet'
:
[
'hello world'
]
}
urlparse和urlsplit
有时候拿到一个url,想要对这个url中的各个组成部分进行分割,那么这时候就可以使用urlparse或者urlsplit来进行分割
首先来看下urlparse
from
urllib
import
parse
url
=
'http://www.baidu.com/s?wb=python&username=abc#1'
result
=
parse
.
urlparse
(
url
)
print
(
result
)
ParseResult
(
scheme
=
'http'
,
netloc
=
'www.baidu.com'
,
path
=
'/s'
,
params
=
''
,
query
=
'wb=python&username=abc'
,
fragment
=
'1'
)
如果仅仅只想获取中间某一个内容,可以使用如下的方式来进行获取
print
(
result
.
scheme
)
http
其次来看下urlsplit
url
=
'http://www.baidu.com/s?wb=python&username=abc#1'
result
=
parse
.
urlsplit
(
url
)
print
(
result
)
SplitResult
(
scheme
=
'http'
,
netloc
=
'www.baidu.com'
,
path
=
'/s'
,
query
=
'wb=python&username=abc'
,
fragment
=
'1'
)
对比可以发现,在使用urlsplit的时候,中间缺少了一个params的参数,这里的params在现在的爬虫中间用到的比较少,这里获取的内容就是 ;和?之间的内容,如下所示
from
urllib
import
parse
url
=
'http://www.baidu.com/s;hello?wb=python&username=abc#1'
result
=
parse
.
urlparse
(
url
)
print
(
result
)
ParseResult
(
scheme
=
'http'
,
netloc
=
'www.baidu.com'
,
path
=
'/s'
,
params
=
'hello'
,
query
=
'wb=python&username=abc'
,
fragment
=
'1'
)
通常情况下,使用urlparse和urlsplit是一样的,唯一不一样的地方就是,urlparse中间多一个params属性,而urlsplit没有这个属性
request.Request类
如果想要在请求的时候增加一些请求头,那么就必须使用request.Request来实现。如果要增加一个User-Agent
from
urllib
import
request
url
=
'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
# resp = request.urlopen(url)
# print(resp.read())
headers
=
{
'User-Agent'
:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
req
=
request
.
Request
(
url
,
headers
=
headers
)
resp
=
request
.
urlopen
(
req
)
print
(
resp
.
read
(
)
)
在上面的代码中,如果想要给请求的url加上一个请求头的话,就需要使用request.Request这个方式将请求的内容进行一个封装,这里封装的请求头是User-Agent这个请求头,这里将这里面的内容写上浏览器的标识;这里需要注意,这里封装好了之后,是还并没有发起请求的,最后还是调用的request.urlopen方法发起请求的
注意:这里的这个request.Request方法除了能够传递User-Agent外,还能够传递data和method
如下:
ProxyHandler处理器(代理设置)
很多网站会检测某一段时间某个ip的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,就会禁止这个ip的访问,所有我们可以设置一些代理服务器,每隔一段时间换一个代理,就算ip被禁止,依然可以换个ip继续爬取
urllib中通过ProxyHandler来设置使用代理服务器,下面代码说明如果使用自定义opener来使用代理
from
urllib
import
request
# 未使用代理
# url = 'http://httpbin.org/ip'
#
# resp = request.urlopen(url)
# print(resp.read())
# -----------------------
# 使用代理的
url
=
'http://httpbin.org/ip'
# 1、使用ProxyHandler,传入代理构建一个handler
handler
=
request
.
ProxyHandler
(
{
'http'
:
'125.110.75.152:9000'
}
)
# 2、使用上面创建的handler构建一个opener
opener
=
request
.
build_opener
(
handler
)
# 3、使用opener去发送一个请求
resp
=
opener
.
open
(
url
)
print
(
resp
.
read
(
)
)
这里需要了解到的就是在使用urlopen的时候,其实也是完成构建一个handler之后再创建了一个opener,最后发起的请求,这个过程只是在openurl中间隐藏了
常用的代理有:
西刺免费代理IP:https://www.xicidaili.com/nt/
快代理:https://www.kuaidaili.com/
代理云:http://www.dailiyun.com/
在需要测试发送请求的机器对应的外网地址,可以使用http://httpbin.org/ip方式获取
小结
1、代理的原理:在请求目的服务器之前,先请求代理服务器,然后让代理服务器去请求目的网站,代理服务器拿到目的网站的数据后,再转发给我们的代码
2、http://httpbin.org:这个网站可以方便的查看http请求的一些请求
3、在代码中使用代理:
3.1 使用 urllib.request.ProxyHandler
3.2 传入一个代理,这个代理是一个字典,字典的key是http或者https,value是ip:port
3.2 使用上一步创建的handler,以及request.build_handler创建一个opener对象
3.3 使用上一步创建的opener,使用open函数,发起请求
什么是cookie
在网站中,http请求是无状态的,也就是说即使第一次和服务器连接后并且登陆成功后,第二次请求服务器依然不能知道当前是哪个用户。cookie的出现就是为了解决这个问题,第一次登陆后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上传请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不操过4KB,因此使用cookie只能存储一些小量的数据
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:是否只在https写一下起作用
下面以访问百度为例
可以看到,cookie都是放在Response Headers中间的
使用cookielib库和HTTPCookieProcessor模拟登陆
Cookie是指网站服务器为了辨别用户身份和进行Session跟踪,而存储在用户用户浏览器上的文本文件,Cookie可以保持登陆信息到用户下次与服务器的会话
这里讲点题外话:
要将byte类型转为str类型,转换过程是byte -> decode -> str
要将str类型转为byte类型,转换过程是str -> encode -> byte
示例:
以上的方式是通过浏览器首先登陆成功之后,在后面页面访问的时候,通过Request Header中间获取到的Cookie,将这个Cookie放在请求头中间,使用代码进行访问
其实这样的方式还不是最好的,Cookie是服务端发出的,此时还是copy的浏览器的Cookie,更好的方式则是通过模拟登陆之后自动保存Cookie,最后携带这个Cookie发起后面的请求