urllib-访问网页的两种方式:GET与POST

学习自:https://www.jianshu.com/p/4c3e228940c8

使用参数、关键字访问服务器

访问网络的两种方法:

1、GET

  • 利用参数给服务器传递信息
  • 参数datadict类型,然后用parse.urlencode()编码为str类型,用编码后data+baseURL构成完整的URL
  • GET中不需要用encode
  • 打开网页
  • 读取页面内容
  • 内容编码转换

2、POST

  • 一般向服务器传递参数使用
  • post把信息自动加密处理
  • 如果想使用post信息,需要用到data参数
  • 使用post,意味着HTTP的请求头请求需要修改:
    • Content-Type:application/x-www.form-urlencode
    • Content-Length:数据长度
    • 简而言之,一旦修改请求方法,请注意与其它请求的头部信息相适应
  • urllib.parse.urlencode可以将dict类型转化为str,encode将str转化为bytes
  • 如果想要设置更多的头部信息,那么urlopen()是无法满足要求的,因此可以用request.Request().add_header(Header信息名,Header信息值)方法
  • request.Request()用来创建Request实例,它包含了所有信息,如url、data、headers、method等。最后只需要用request.urlopen()打开这个实例即可。

3、urllib.error

当使用request进行爬虫时,尽量采用try...except代码块,并把爬虫代码放入try中,避免错误。

  • URLError产生的原因
    • 没网络
    • 服务器链接失败
    • OSError的子类

 

  • HTTPError
    • URLError的子类

 

  • 两者区别
    • HTTPError是对应的HTTP请求返回的错误
    • URLError对应的是一般的网络问题,包括URL错误
    • 继承关系有:OSError - URLError - HTTPError

 

GET访问方式

1、parse.urlencode()的简单应用

在使用搜索引擎时,如搜索“学习Python”,当搜索结果出来后,可以在URL地址栏发现如下的URL字符串:

https://www.baidu.com/s?wd=学习Python&...#后边省略

如果我们只保留其中主要的部分

https://www.baidu.com/s?wd=学习Python

其搜索结果还是一样的。

 

这就说明,在使用搜索引擎时,前面的 'https://www.baidu.com/s?' 是固定不变的,为baseURL,只需要输入关键字即可返回结果。

此时,在浏览器中按F12进入开发者模式,查看Network->Name栏的Headers部分。这里就是HTTP请求头Header的信息内容。

 

 可以看到,“学习”二字变成了一串由16进制字符组成的字符串%E5%AD%A6%E4%B9%A0,说明浏览器在发送请求时对URL进行了编码

①利用parse模块模拟GET请求

在使用爬虫时,可以只需要输入关键字,并且将关键字进行编码,将其转换成服务器识别的形式,最后把关键字baseURL连接起来即可实现访问。

这里的编码采用的方法就是parse模块下的parse.urlencode()方法。

复制代码
from urllib import parse,request

baseURL='https://www.baidu.com/s?'

wd=input('Input your keyword:')

#这里必须是wd,不能是其他的字符串
data={'wd':wd}
data=parse.urlencode(data)

URL=baseURL+data

with request.urlopen(URL) as f:
    html=f.read().decode('utf-8')

print(html)
复制代码

运行程序,输入“学习Python”,结果:

最终的URL: https://www.baidu.com/s?wd=%E5%AD%A6%E4%B9%A0Python
<!DOCTYPE html>
        <html>
        <head>
        </head>
        <body>
        </body>
</html>

打印出来的结果就是html文档文件,也就是搜索“学习Python”后的网页内容。

同时也能看到最终提交到服务器端的URL地址,其中“学习Python”中的汉字已经转化为bytes类型了,这就是parse.urlencode()的作用。

注意:

1、baseURL最后是/s?而不是/?s

2、输入的关键字,必须存储为wd,不能自定义为其他的变量名

3、编码前要先把关键字wd添加到一个dict对象中去,对得到的dict对象编码

data={'wd':wd}

4、两个关键语句:

data=parse.urlencode(data)

with request.urlopen(URL) as res:
    html=res.read().decode('utf-8')

其中,①parse.urlencode的参数必须是dict对象

request.urlopen(URL)获取URL句柄,标记为对象res

对句柄res调用read()获取最原始的信息,res.read()

对原始信息进行解码后显示:res.read().decode()

5、从服务器端读取的内容为bytes类型,要用decode将之转化为str类型,才能打印出来。

 

POST访问方式

post方式访问,是提交表单类的数据到服务器。

 

request.urlopen()中的data参数

百度翻译举例使用data参数:

 

利用parse模块模拟POST请求:

  • 首先进入百度翻译首页,并用F12进入开发者模式,查看Network栏
  • 输入单词girl,可以发现每输入一个字母后边都有请求

 

 

  • 请求地址是:https://fanyi.baidu.com/sug
  • 请求方式是:POST

 

  • Form data的值是kw:girl,所以字典的Key名为kw(这点注意与get中的Key名为wd相区分)
  • 查看返回内容格式,content-length是返回内容长度;content-type是返回内容格式——返回的是json格式内容,需要用到json包

 

 

利用parse模拟POST请求

步骤:

  • 利用data参数构造内容,这里的内容就是之前所说的关键字内容Form data
  • 使用request.urlopen(url , data)打开url,并传入内容data;baseURL不需要data连接以构成一个完整的URL
  • 返回的JSON数据类型,用json.loads()转换为str字符串类型
  • 返回的结果就是搜索词的释义
复制代码
from urllib import parse,request,error

#返回内容为JSON格式,用json.loads()转换为str
import json

#基本URL
baseURL='https://fanyi.baidu.com/sug'

#为防止报错,使用try...except语句块,使用error.URLerror
try:
    #输入Form data
    kw=input('Input your keyword:')

    #用data存放Form data;Request传入的数据必须是字典类型
    #浏览器中开发模式下,Form data下字典的Key为kw,所以data的Key为kw
    data={'kw':kw}

    data=parse.urlencode(data).encode()
    print('即将发送的data数据的类型:',type(data))

    #打开网页,传入data参数
    #urlopen的参数为baseURL和data参数
    with request.urlopen(baseURL,data=data) as res:
        json_data=res.read().decode()
        print('返回数据的类型:',type(json_data))
        json_data=json.loads(json_data)
        print('转换后的数据类型:',type(json_data))

        for i in json_data['data']:
            print(i)
except error.URLError as e:
    print(e)
复制代码

 结果:

复制代码
Input your keyword:>? Girl
即将发送的data数据的类型: <class 'bytes'>
返回数据的类型: <class 'str'>
转换后的数据类型: <class 'dict'>
{'k': 'girl', 'v': 'n. 女孩; 姑娘; 女儿; 年轻女子; 女郎;'}
{'k': 'girls', 'v': 'n. 女孩; 姑娘; 女儿; 年轻女子; 女郎;  girl的复数;'}
{'k': 'girlfriend', 'v': 'n. 女朋友; 女情人; (女子的)女伴,女友;'}
{'k': 'girl friend', 'v': ' 未婚妻; 女性朋友;'}
{'k': "Girls' Generation", 'v': ' 少女时代(韩国SM娱乐有限公司于2007年推出的九名女子少女组合);'}
复制代码

这就是使用parse模拟浏览器访问服务器的用法。

补充:

1、最开始传入的data为dict类型,最后返回的数据也是转化为dict类型

2、Post的传入关键字构建dataKey必须命名为爬虫页开发者模式下的Form data

3、url.urlencode(data),将原始的dict转化为str类型;encode('utf-8'),将str类型转化为bytes类型;服务器接收的类型为bytes类型,所以中间将data进行类型转化的语句是:

data=parse.urlencode(data).encode() #encode参数缺省时默认为'utf-8'

此时的data为bytes类型,可以向服务器发送了

4、发送——request.urlopen(baseURL,data=data)

with request.urlopen(baseURL,data=data) as res:
                json_data=res.read()

用json_data接收返回信息。此时json_data为bytes类型,要通过decode()解码为str类型,再通过json.loads()函数变为dict类型。

(实际应用时,我发现不用decode()解码,直接对read()的结果进行json.loads(),同样可以返回一个正常的dict对象,不知道以后有没有影响?)

5、为防止报错,可以用try...except程序块

6、这里的urlopen中的URLbaseURL,与data各自为urlopen两个参数不用连接成为一个完整的URL

 7、有的网站返回的数据不是json类型,这时候就不能用json.load了,具体类型应去网页中通过F12开发者模式header->Content-Type获知。

 

request.Request(url= , data= , heads=  , method='POST'/'GET')

request.urlopen()的功能有限,如果我们想为请求头部添加更多的设置信息,如“Content-Length”,那么用urlopen()是无法实现的。

因此,在此基础上,我们可以使用request.Request(),它的功能与urlopen()类似,可以打开网页,但比urlopen()优秀的是,它可以为请求头部自定义信息,无限扩展功能。

于是,在上面代码的基础上,可以修改一番:定义一个headers用以存放自定义的头部信息,然后用request.Request()创建一个Request实例,该实例将所有信息全部包括,到最后只需要用urlopen()打开这个实例即可。

另外,如果想要往该Request实例中补充headers,假设该实例名为req,则可以用方法add_header()实现:

req.add_header(Key , Value)

但需要注意的是add_header的Key-Value必须是合法的,不合法的header会导致其他错误!

复制代码
from urllib import request,error,parse
import json

baseURL='https://fanyi.baidu.com/sug'

kw=input('Input your keyword:')

data={'kw':kw}

data=parse.urlencode(data).encode()

#构造headers,这里的header是自定义要访问的,如模拟浏览器访问服务器
#构造的headers中,至少包含Content-Length
#传入Request参数的data和headers都是dict类型
headers={'Content-Length':len(data)}

#用request.Request模拟浏览器访问服务器
#requset.Request()构造了一个Request实例,其中可以包含大量header内容
#URL为baseURL,data为输入的关键字参数,这里不用连接成一个完整的URL
req=request.Request(baseURL,data=data,headers=headers,method='POST')


#添加一个User-Agent的Header信息 req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25') #最后用urlopen()打开该实例即可 try : with request.urlopen(req) as res: json_data=res.read() rec=json.loads(json_data) for k in rec['data']: print(k) except error.URLError as e: print(e)
复制代码

 

结果与之前的相同。

比urlopen()好的是,Request可以无限扩展功能,模拟浏览器访问服务器,不仅如此,对于之后的身份隐藏等操作,也只需在headers中设置即可。

Post爬虫的基本操作流程:

①使用data参数创建内容(需要搜索的内容)

②用parse.urlencode和encode进行转码

③用urlopen或者request.Request打开URL,并传入data

④返回结果

⑤对结果进行其他操作

 

总结:

1、关键字参数(需要搜索的内容比如data)必须是dict类型,发送请求时,首先用parse.urlencode(data),将dict类型转化为str,再用encode()将str转化为服务器接收的bytes类型。

而把接收到的数据转化时,需要先read(),再decode(),再json.loads()。(实际应用时,发现不用decode()一样可以得到相同结果,推测可能是json.loads()的作用。暂不知道这样做有没有副作用)

2、想要对某个网页进行爬虫操作,需要用F12打开开发者模式,查看这个页面的信息。主要信息是:请求URL访问服务器的方式返回数据的格式(如果是JSON,需要用json模块转化)Form data 如果有该项,要确定参数的Key名

3、dict类型:Request参数的data、headers;urlopen参数的data

4、GET与POST在程序中的最大区别是:

GET中的urlopen的参数只有URL(可能有headers)

POST中的urlopen的参数是URL+data(可能有headers)dataPOST请求的数据

复制代码
#GET
req=request.Request(URL)
with request.urlopen(req) as res:
        ...

#POST
req=request.Request(baseURL , data=data , headers=headers , method = 'POST')
with request.urlopen(req) as res:
        ...
复制代码

5、header不是GET与POST的区别,这两种请求均可以加header

方式是:

 

req=request.Request(URL,headers=headers)

 

header的目的是通过加首部信息模拟浏览器服务器访问

 

6、有的网站返回的数据不是json类型,这时候就不能json.load了,具体类型应去网页中通过F12开发者模式header->Content-Type获知。

比如:访问百度首页时的请求,就是html类型

 

posted @   ShineLe  阅读(2060)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示