学习自: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类型

最新文章

  1. Android 添加ActionBar Buttons
  2. 【刷题记录】 &amp;&amp; 【算法杂谈】折半枚举与upper_bound 和 lower_bound
  3. kuangbin_SegTree E (HDU 1698)
  4. 【CodeForces 621A】Wet Shark and Odd and Even
  5. .NET中资料库的设计与SQL
  6. What are the 10 algorithms one must know in order to solve most algorithm challenges/puzzles?
  7. java 地址记录
  8. R语言快速入门
  9. 15、自定义Content Provider
  10. Java并发编程:进程和线程之由来__进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能
  11. frame模型
  12. Ajax实现动态的二级级联菜单
  13. Android的Binder的起源-android学习之旅(100)
  14. QQ登录界面布局
  15. debug错误
  16. scrapy-items
  17. centos7 安装搜狗输入法
  18. [leetcode]Partition List @ Python
  19. 【嵌入式】FS2410非操作系统外围资源测试
  20. MongoDB(四)-- 主从配置

热门文章

  1. IntelliJ IDEA 热部署,修改java文件 不用重启tomcat
  2. setcontext+orw
  3. 深度评测丨 GaussDB(for Redis) 大 Key 操作的影响
  4. python08day
  5. python02day
  6. Vue3.2中的setup语法糖,保证你看的明明白白!
  7. Python初学笔记列表&amp;元组&amp;字典
  8. 2020-11-21 f
  9. AT5760 Manga Market
  10. CF1399F Yet Another Segments Subset