urllib-访问网页的两种方式:GET与POST
学习自:https://www.jianshu.com/p/4c3e228940c8
使用参数、关键字访问服务器
访问网络的两种方法:
1、GET
- 利用参数给服务器传递信息
- 参数data为dict类型,然后用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的传入关键字构建data的Key必须命名为爬虫页开发者模式下的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中的URL为baseURL,与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),data为POST请求的数据
#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类型
urllib-访问网页的两种方式:GET与POST的更多相关文章
- Servlet访问路径的两种方式、Servlet生命周期特点、计算服务启动后的访问次数、Get请求、Post请求
Servlet访问路径的两种方式: 1:注解 即在Servlet里写一个@WebServlet @WebServlet("/myServlet") 2:配置web.xml < ...
- JS中访问对象的两种方式区别
可以使用下面两种方式访问对象的属性和方法 1.对象名.属性名 对象名.方法名() 2.对象名["属性名"] 对象名["方法名"]() var obj = { n ...
- WPF内嵌网页的两种方式
在wpf程序中,有时会内嵌网页.内嵌网页有两种方法,一种是使用wpf自带WebBrowser控件来调用IE内核,另一种是使用CefSharp包来调用chrom内核. 一.第一种使用自带WebBrows ...
- .NET访问数据库的两种方式(C#语言)
一.直接使用C#操作数据库的类库ADO.NETADO.NET使用Connection对象来连接数据库,使用Command或DataAdapter 对象来执行SQL语句,并将执行的结果返回给DataRe ...
- Spring框架访问数据库的两种方式的小案例
1.1 以Xml的方式访问数据库的案例 要以xml的方式访问数据库需要用到JdbcTemplate ,因为 JdbcTemplate(jdbc的模板对象)在Spring 中提供了一个可以操作数据库的对 ...
- ado ole方式访问access的两种方式
OleDbConnection Connection = new OleDbConnection(); OleDbDataAdapter adapter = null; //ConnectiongSt ...
- System.Web.Http.Cors配置跨域访问的两种方式
System.Web.Http.Cors配置跨域访问的两种方式 使用System.Web.Http.Cors配置跨域访问,众多大神已经发布了很多文章,我就不在详细描述了,作为小白我只说一下自己的使用心 ...
- Nginx配置同一个域名同时支持http与https两种方式访问
Nginx配置同一个域名http与https两种方式都可访问,证书是阿里云上免费申请的 server{listen 80;listen 443 ssl;ssl on;server_name 域名;in ...
- JavaScript对象属性访问的两种方式
JavaScript对象属性访问的两种方式 object.attribute object["attribute"] 例如: var employees = [ { "f ...
随机推荐
- 如何修改主机名hostname
hostname是Linux系统下的一个内核参数,它保存在/proc/sys/kernel/hostname下,但是它的值是Linux启动时从rc.sysinit读取的.而/etc/rc.d/rc.s ...
- Avoiding the Backup of Online Redo Logs
Although it may seem that you should back up online redo logs along with the datafiles and control f ...
- Pytest单元测试框架生成HTML测试报告及优化
一.安装插件 要生成html类型的报告,需要使用pytest-html插件,可以在IDE中安装,也可以在命令行中安装.插件安装 的位置涉及到不同项目的使用,这里不再详述,想了解的可自行查询. IDE中 ...
- 来自开发者的点赞!HMS Core荣获多个行业奖项
2021年,HMS Core发布全新HMS Core 6,为全球开发者提供多终端.跨OS.全场景的华为移动服务核心能力,和开发者共同成长.通过和开发者在行业解决方案.业务场景创新和商业增长上的持续合作 ...
- AT2699 [ARC081D] Flip and Rectangles
以下是简要题解: 首先思考如何判定一个矩形是否能通过操作变成全黑. 首先从简单而又特殊的 \(2 \times 2\) 的矩形开始,不难发现只要其中黑色数量不为奇数即可. 近一步拓展可以发现,一个矩形 ...
- JVM学习十四 - (复习)类文件结构
类文件结构 JVM 的"无关性" 谈论 JVM 的无关性,主要有以下两个: 平台无关性:任何操作系统都能运行 Java 代码 语言无关性: JVM 能运行除 Java 以外的其他代 ...
- JVM学习四:深入分析ClassLoader
一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...
- 使用UrlConnection请求一个url地址获取内容
访问网络需要加Internet权限:android.permission.INTERNET 使用UrlConnection请求一个url地址获取内容: //1.创建一个Url对 ...
- 长安战疫Wp
长安战疫wp misc 八卦迷宫 直接走迷宫 cazy{zhanchangyangchangzhanyanghechangshanshananzhanyiyizhanyianyichanganyang ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...