爬虫(02)网络请求模块2020-12-14

1. 几个概念

1.1 get和post

爬虫有两种主要的请求方式就是get和post,get的请求方式,请求参数都会在url里面显示出来,而post则不会。一般post会对服务器数据产生影响,比如登录的时候会提交账户和密码,这个时候需要用post请求。

1.2 全球统一资源定位符

通称URL
例如下面是一个新闻网页的url:
https://news.cctv.com/2020/12/13/ARTILDC3agyCVhXCYNdc8Alu201213.shtml?spm=C94212.P4YnMod9m2uD.E7v7lEZZ0WEM.4
我们研究一下他的组成部分

http: 协议
news.cctv.com: 主机名  这里省略了一个端口443
2020/12/13/ARTILDC3agyCVhXCYNdc8Alu201213.shtml?spm=C94212.P4YnMod9m2uD.E7v7lEZZ0WEM.4    这是我们所访问资源的一个路径

anchor  拓展,这个是锚点,做导航的,定位到某个目录  (拓展知识点)

浏览器去请求一个url的时候,除了英文字母,数字和部分符号外,其他的都采用%加16进制来进行编码。因为网站只能识别ascall码。如果携带中文的时候,会被编码。

1.3 User-Agent

用户代理,记录了用户的操作系统,浏览器版本等信息,为了让用户获得更好的页面浏览效果。爬虫时将User-Agent作为header加入,会增加成功率。
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0

Gecko 这个时指浏览器的内核

1.4 Referer

我们在header里面还发现了Referer: https://www.lagou.com/这是一个跳转记录,显示本页面是由哪个页面跳转来的。也是和反爬虫有关的,如果你请求的时候,没有这个元素,则服务器认为你是爬虫程序,而不是从浏览器跳转来到这个页面的。所以这个元素也要添加到header里面,可以增加请求的成功率。

当然,后面还有关于Cookie、seccion等中还要知识点,后面专题来讲。

2. 状态码

200 请求成功
301 永久重定向
302 临时重定向
404 服务器无法响应
500 服务器内部请求

3. 抓包工具里的选项

elements: 元素,网页源代码,用于提取数据和分析数据(注意,有些数据是经过处理的,并不准确)
Console: 控制台,可以编码,打印信息。
Sources: 是整个网站资源的加载来源。
Network: 可以看见很多的请求信息,可以用来分析数据接口

4. urllib

  • 有些比较老的爬虫项目用的还是urllib技术,如果没有见过,你不知道怎么更新。
  • 有时候在爬取有些数据的时候,需要urllib+requests一起使用的。
  • 而且urllib是内置的。
  • urllib在某些方面作用还是比较强大的。
    基于以上四个原因,我们还是有必要学习一下urllib
    下面我爬取一张图片
import requests
url = 'https://c-ssl.duitang.com/uploads/item/202007/19/20200719141153_kyfng.jpg'
res = requests.get(url)
tu = open(r'C:\Users\MI\OneDrive\桌面\pic.jpg','wb')
tu.write(res.content)
tu.close()

执行结果是在我的桌面上出现了一张名为pic的图片。
在这里插入图片描述
当然,也可以这样子写:

import requests
url = 'https://c-ssl.duitang.com/uploads/item/202007/19/20200719141153_kyfng.jpg'
res = requests.get(url)
with open(r'C:\Users\MI\OneDrive\桌面\pic01.jpg','wb') as tu:
	tu.write(res.content)

执行结果是一样的。
方式二,用urllib

from urllib import request
url = 'https://c-ssl.duitang.com/uploads/item/202007/19/20200719141153_kyfng.jpg'
request.urlretrieve(url,r'C:\Users\MI\OneDrive\桌面\pic02.png')

执行结果

在这里插入图片描述
所以我们看到,这里用urllib好像更方面,都不需要open()函数了。

4.1 urllib的用法

python2:urllib2, urlib
python3: 把urllib和urllib2合并成urllib.request
常用方法:

response = urllib.request.urlopen('网址')

作用,向一个网站发起请求,并获取响应。

字节流 = response.read()
字符串 = response.read().decode('utr-8')

下面我爬取一下百度网页

# 爬取百度网页
import urllib.request
url = 'https://www.baidu.com'
response = urllib.request.urlopen(url)
 # 下面用read()方法把响应对象里面的内容读取出来
html = response.read()
 # 打印一下所读处的内容的类型和内容
print(type(html),html)

结果

<class 'bytes'> b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body>\r\n</html>'

我们看到返回结果是字节流,如果我们想改成字符串,可以这样:

import urllib.request
url = 'https://www.baidu.com'
response = urllib.request.urlopen(url)
html = response.read().decode('utf-8')
print(type(html),html)

结果

<class 'str'> <html>
<head>
	<script>
		location.replace(location.href.replace("https://","http://"));
	</script>
</head>
<body>
	<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>

这样可读性更强了。而且返回类型是字符串类型。但是我们发现里面没有什么内容,这是因为百度的反爬机制。我们可以加一个headers伪装成浏览器。

那么我们把上面的代码改成下面的可以码:

import urllib.request
url = 'https://www.baidu.com'
headers = {‘User-Agent’:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36’}
response = urllib.request.urlopen(url,headers=headers)
html = response.read().decode('utf-8')
print(type(html),html)

结果报了一个这样的错

Traceback (most recent call last):
  File "D:/work/爬虫/Day02.py", line 45, in <module>
    response = urllib.request.urlopen(url,headers=headers)
TypeError: urlopen() got an unexpected keyword argument 'headers'

说urlopen()方法不希望得到一个参数’headers’就是说,这里啊,不支持传参headers。那么怎么办呢?

4.2 urllib.request的headers传参流程

urllib.request的headers传参流程如下,仔细看注释:

import urllib.request
url = 'http://www.baidu.com/'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36'}
# 1.创建请求对象,用request里面的Request方法传参headers
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象,
response = urllib.request.urlopen(req)
# 3.读取响应对象的内容read().decode('utf-8')
html = response.read().decode('utf-8')
# 4.打印结果
print(html)

这一次拿到的结果就多一些了,我就不全部展示了,只截取片段:

"https%3A//www.baidu.com/s%3Fcl%3D3%26tn%3Dbaidutop10%26fr%3Dtop1000%26wd%3D%25E9%2598%25BF%25E9%2587%258C%25E5%25B7%25B4%25E5%25B7%25B4%25E9%2598%2585%25E6%2596%2587%25E4%25B8%25B0%25E5%25B7%25A2%25E5%2590%2588%25E8%25AE%25A1%25E8%25A2%25AB%25E7%25BD%259A150%25E4%25B8%2587%26rsv_idx%3D2%26rsv_dl%3Dfyb_n_homepage%26hisfilter%3D1","views": "","isViewed": "","isNew": "","heat_score": "2839181","hotTags": "1"},{"pure_title": "游客凤凰古城租衣服被禁止自拍","linkurl": "https%3A//www.baidu.com/s%3Fcl%3D3%26tn%3Dbaidutop10%26fr%3Dtop1000%26wd%3D%25E6%25B8%25B8%25E5%25AE%25A2%25E5%2587%25A4%25E5%2587%25B0%25E5%258F%25A4%25E5%259F%258E%25E7%25A7%259F%25E8%25A1%25A3%25E6%259C%258D%25E8%25A2%25AB%25E7%25A6%2581%25E6%25AD%25A2%25E8%2587%25AA%25E6%258B%258D%26rsv_idx%3D2%26rsv_dl%3Dfyb_n_homepage%26hisfilter%3D1","views": "","isViewed": "","isNew": "","heat_score": "2739810","hotTags": "0"},{"pure_title": "男子骑马从新疆伊犁回福建老家","linkurl": "https%3A//www.baidu.com/s%3Fcl%3D3%26tn%3Dbaidutop10%26fr%3Dtop1000%26wd%3D%25E7%2594%25B7%25E5%25AD%2590%25E9%25AA%2591%25E9%25A9%25AC%25E4%25BB%258E%25E6%2596%25B0%25E7%2596%2586%25E4%25BC%258A%25E7%258A%2581%25E5%259B%259E%25E7%25A6%258F%25E5%25BB%25BA%25E8%2580%2581%25E5%25AE%25B6%26rsv_idx%3D2%26rsv_dl%3Dfyb_n_homepage%26hisfilter%3D1","views": "","isViewed": "","isNew": "","heat_score": "2643916","hotTags": "0"},{"pure_title": "李国庆称30天离婚冷静期不可怕"

总结,用urllib.request来传参headers需要先创建一个请求对象,里面用的Request方法来传参headers。然后用urllib.request.urlopen()方法来打开请求对象获取响应结果。最后用read().decode(‘utf-8’)来读取响应内容并解码。

 # 4.获取状态码和url
print(response.getcode())
print(response.geturl())

结果

200
https://www.baidu.com/

4.3 urllib.parse的使用

我们在百度帖吧搜索”海贼王”

https://tieba.baidu.com/f?fr=ala0&kw=%BA%A3%D4%F4%CD%F5&tpl=5

这是搜索时地址栏产生的链接
可以看到后面是%+16进制数组成的,我们可以使用urllib.parse中的urlencode方法对其进行转换。

# 搜索“海贼王”
url = 'https://tieba.baidu.com/f?ie=utf-8&kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&fr=search'

import urllib.parse
tu = {'wd':'海贼王'}
res = urllib.parse.urlencode(tu)  # 记得这里传入的是一个字典
print(res)

结果

wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B

可以看到跟url里面的一部分是相同的。
这个知识点可以用在构建url里,对以后爬虫很有用。

5. 项目实操

5.1 构建url

我们现在百度t贴吧里面随便输入一个什么来搜索,研究其url构成,比如输入“小狗”,把地址栏的url复制下来以分析:

https://tieba.baidu.com/f?ie=utf-8&kw=%E5%B0%8F%E7%8B%&fr=search

大家仔细看代码中的注释:

import urllib.request
import urllib.parse
base_url = 'https://tieba.baidu.com/f?ie=utf-8&'  # 创建基本url,后面的内容是可变的。
 # %E7%BE%8E%E5%A5%B3&fr=search    # 这一部分前面是16进制数,是我们要输入的关键字
key = input('请输入你要搜索的内容:')
kw = {'kw':key}
key = urllib.parse.urlencode(kw)  # 对输入内容进行编码
url = base_url+key+'&fr=search'  # 重新构建新的url
print(url)

比如我们输入“老师”就会得到一个搜索老师的url

https://tieba.baidu.com/f?ie=utf-8&kw=%E8%80%81%E5%B8%88&fr=search

点击就可以进入页面。
这里再次强调urllib.parse.urlencode()里面传入的是一个字典
下面有个quote()里面传入一个字符串。

import urllib.request
import urllib.parse
base_url = 'https://tieba.baidu.com/f?ie=utf-8&kw='  # 创建基本url,注意这里要加上kw=
 # %E7%BE%8E%E5%A5%B3&fr=search    # 这一部分前面是16进制数,是我们要输入的关键字
key = input('请输入你要搜索的内容:')

key = urllib.parse.quote(key)  # 对输入内容进行编码
url = base_url+key+'&fr=search'  # 重新构建新的url
print(url)

执行结果

请输入你要搜索的内容:老师
https://tieba.baidu.com/f?ie=utf-8&kw=%E8%80%81%E5%B8%88&fr=search

5.2 项目:搜索一个关键字并存储

下面我们实操一个项目,模拟百度,输入关键字,可以在百度百科里搜索想要的内容,并存储:

# 输入关键字,搜索并存储爬取内容

import urllib.request
import urllib.parse

headers = {
    'User-Agent': ' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}

# url = https://baike.baidu.com/item/%E5%AD%A6%E7%94%9F
base_url = 'https://baike.baidu.com/item/'
kw = input('请输入你要搜索的内容:')
kw = urllib.parse.quote(kw)
url = base_url + kw
req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
html = response.read().decode('utf-8')
print(url)
with open(r'D:\spiderdocuments\demo_01.txt', 'w',encoding = 'utf-8') as f:
    f.write(html)

结果在我的D盘中的txt文档中就写入了我爬取的内容。
在这里插入图片描述
本次课到此结束。

猜你喜欢

转载自blog.csdn.net/m0_46738467/article/details/111150385
今日推荐