request简介
python 爬虫最基础的实现就是由内部的request模块完成的,模块集成了发送网络请求,获取网络数据等功能,接下来就来对request来进行简单地了解
首先说一下什么叫做http,较为官方的解释是超文本传输协议,那么超文本传输协议究竟又是什么东西?
HTTP与HTTPS
其实我们的客户端和服务端进行数据传输的过程中都是通过二进制数据来进行沟通的,那么http协议就是一种客户端和服务端传输数据的一种形式,就http协议而言,其本身有几个特性,无状态(不会记录上次传输内容),无连接(传输结束后会列断开连接),可传输任意形式的数据与媒体独立。至于https协议是基于http协议加上SSL密钥加密的一种更高级的传输协议罢了。
加密方式
既然提到了密钥的加密那么也应该说说集中密钥加密方式。
首先是对称密钥也就是SSL加密方式,在客户端与服务端进行数据传输的过程中由一端进行数据加密,然后密钥会随着数据的传输一同到达另一端,然后由接收端根据密钥进行解密,但是这种传输方式的缺点就显得比较明显,当发生数据劫持的时候密钥会随着被加密的数据一同被劫持,这样就很大程度上会发生数据的泄露。于是这种密钥加密方式被随之升级。
非对称加密方式:在对称密钥加密的缺点被放大之后,安全度更高的非对称加密问世,首先有服务端生成一组密钥,其中包含了公钥与私钥,接下来服务端像客户端发送公钥,由客户端根据所获得的密钥生成一段私钥,通过客户端所生成的私钥对所要传输数据进行加密,在服务端获取数据之后再根据其自身私钥进行解密从而拿到数据。
对整个过程进行详细的解读大概就是会有三个密钥生成,分别是服务端的公钥与私钥,以及客户端根据服务端公钥所产生的私钥,其中公钥的作用就不言而喻,而客户端的私钥主要用于传输数据的加密,而服务端的私钥主要是用于对传输数据的解密。
基于SSL证书非对称加密方式:相信大家都会遇到过访问网页的时候会提示网页安全证书已经被吊销的提醒,那么什么是安全证书?在上述服务端自己生成公钥的方法中缺陷还是明显的,就是在数据传输过程中我们还是不可避免的要携带密钥,这是一个很严重却无法解决的问题,而SSL证书一定程度上解决了这个问题。首先由开发者向数字证书申请机构递交申请,而符合申请规则的会被返回一个数字证书,其中包含了公钥,私钥。这就意味着我们的公钥与私钥都不在由我们自己生成,而服务端会像客户端发送这个证书,客户端会根据证书来进行真伪校验,同时用证书所提供的公钥进行传输数据的加密,然后服务端会根据私钥进行解密。在整个过程中密钥都是不会暴露给外界的。
普及了基础的网络知识后就来详细的了解一下基于python的网络爬虫
网络爬虫开篇
什么是网络爬虫?:用来爬取数据的的工具,如今数据充斥在我们身边的所有环境之中可见数据对我们的影响有多大,所以我们需要通过一种方便快捷的方式来获取网上所流通的数据所以网络爬虫应运而生。
其实在生活中我们在许多地方都在使用网络爬虫,再夸张的说可以说网络爬虫影响着我们的生活已经很久了。
网络爬虫的分类:
1.通用爬虫:搜索引擎的重要部分,他们会爬取整个互联网的数据然后备份镜像到本地,对网页进行简单处理之后提供一个统一的接口对外开放这些数据。
2.聚焦爬虫:爬虫的范围不再是整个互联网,而是有针对性的对某些页面的某些数据进行抓取。
3.反爬虫:为了防止被爬取数据,门户自带的一些策略
用Python爬取数据
我们将在这里介绍利用python中的一些专职模块来进行网络数据的爬取同时会在一些地方穿插一些反爬机制,比如我在request模块之前要介绍的两种反爬机制:
1.robots.txt:一种约定俗成的协议(虽然并没有什么卵用),它规定了当前页面那些数据是可以共享的那些数据是隐私的,那些数据是登陆之后依然隐私的(然而没有人去遵守)
2.请求头之UA认证:在web开发中我们都应该知道,请求头的概念,他是一个请求的开始位置,包含了这次请求除了交互数据之外的一些配置相关信息。当我们请求一些数据的时候会发现请求页面404,当然你首要检查的应该是你的网络,然后就要考虑到你的请求头中是否携带了UA信息(当然如果两样你都做了那么还会有其他的反爬机制阻止你,我们之后再细聊)USER-AGENT:'xxxx'请求头中较为重要的信息,大家应该都清楚,我们的爬虫实质上就是模拟浏览器向目标页面发起请求,其中请求头中的USER-AGENT中携带了浏览器版本等一系列信息,如果我们没有自定义这个字段,会被网页认为是非法用户而拒绝我们的访问。我们只需要一个字段,当然它的值你可以去网上查,或者干脆打开你浏览器的开发界面拿都可以,就可以避免这种情况的发生。
介绍完了两种较为常见的反爬机制(说实话我不知道第一种算不算是,但是很多博主都会算上他,我感觉更像是一种精神伤害)我们开始介绍request模块。
如果你和我一样事先接触的web开发而后才开始接触爬虫,那么你的学习可能就会轻松一点,request请求是python中使用频率比较高的一个模块,模块会为你自动整合url拼接headers像目标地址发送get or post请求,相较于urllib需要手动进行这些操作确实要方便的多,我们通过几个案例来进行request的实操。
1.对百度进行简单的一次get请求
import requests #首先导入requests模块 headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" } #这就是之前说到过的UA认证机制 url = "https://www.baidu.com" #请求的目标地址 response = requests.get(url=url,headers=headers).text #想目标地址发送请求且将相应数据赋值给一个变量,这里要注意的是我们请求回来的是一个response(响应)对象,所以我们需要.text来获取内容 print(response)
至此我们进行了一次简单地request操作,接下来我们将尝试get请求携带参数
2.像百度搜索框中添加数据,并得到搜索页面返回结果
首先进行分析我们在进行搜索框搜索之后跳转的页面url为https://www.baidu.com/s?ie=UTF-8&wd=robots.txt通过我们之前所积累的web知识我们知道本次get请求我们所需要携带的参数是?后面的ie与wd(说实话我第一次请求的时候并没有携带ie但是也成功了,可最终我们是需要严谨对待的,百分百还原浏览器请求过程)
import requests headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" } wd = input('请输入要搜索的内容') params = { 'ie':'UTF-8', 'wd':wd }#携带的动态请求参数 url = 'https://www.baidu.com/s' response = requests.get(url=url,headers=headers,params=params).text print(response)
3.通过post请求来获取kfc店铺的详细位置信息
post与get最大的区别就是在于携带数据,那么很多小伙伴不清楚自己对目标发起请求是get还是post。其实对于w有web开发经验的朋友们来说都知道一般这种情况都是要抓包解决,具体来说就是通过浏览器抓包工具来进行分析的,因为爬虫归根结底来说就是模仿浏览器像服务端发送请求以获取数据,所以我们使用浏览器的检查功能打开控制台找到浏览器传输数据的行为然后在同一分析。
综上所述我们通过谷歌浏览器的自带抓包工具能够得知我们在对kfc发送请求时所携带的数据以及请求方式。
可是我们发现当前数据的获取并没有在明面上,也就是我们在当前页面是获取不到数据的,这也是一种反扒机制,也就是ajax提交动态数据获取。
反扒3动态数据:我们在当前页面找不到我们所需要的数据,但是页面上确确实实给我们显示了这些,原因就是ajax动态的获取了这些数据,换句话说我们所访问的页面是一个在动态加载的页面,这时,我们需要对齐进行网络请求分析来找到我们所需要的目标请求地址,以及他返回的数据格式和内容
通过分析我们得知我们所需要的数据地址是http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword,那么之后我们仅需要根据相应的数据格式和请求方式来对目标地址发送请求就可以了
import requests headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" } url="http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword" for page in range(1,6): data = { 'cname': '', 'pid': '', 'keyword': '北京', 'pageIndex': page, 'pageSize': '10', } all_data = requests.post(url=url,headers=header,data=data).json()["Table1"]#携带数据的post请求 for dic in all_data: addr = dic['addressDetail'] name = dic['storeName'] print(addr, name)
大家可以去尝试用这种方式去搜索一下华为荣耀的店面信息
4.图片的加载
在图片加载我们推荐使用urllib中的request请求,因为在下载文件方面urllib还是具有一定优势的,同时为大家引入一个新的模块 python中的ssl认证模块
在urlib中的request我们可以通过实现封装好的urlretrieve方法通过传递图片存储的路径,名字以及图片本身数据快速的完成图片下载功能,而对于一些https协议的界面我们就需要关闭证书的验证来完成对页面的请求
import os import ssl #导入ssl模块 ssl._create_default_https_context = ssl._create_unverified_context #关闭ssl证书验证 from lxml import etree tree = etree.parse('./test.html') print(tree.xpath("/html/head/title")) print(tree.xpath("//a[@id='feng']")) print(tree.xpath("//div[@class='song']/p[3]/text()")[0]) dirName = 'girlLib' if not os.path.exists(dirName): os.mkdir(dirName) main_url = "http://pic.netbian.com/4kmeinv/" response = requests.get(main_url,headers=header) response.encoding = "gbk" page_text =response.text tree = etree.HTML(page_text) img_list = tree.xpath("//div[@class='slist']/ul/li/a/img") for img in img_list: img_src = "http://pic.netbian.com"+img.xpath("./@src")[0] img_name = img.xpath("./@alt")[0]+".jpg" img_data = requests.get(img_src,headers=header).content # print(img_data) img_path = dirName+"/"+img_name with open(img_path,"wb") as f: f.write(img_data) # print("sucess",img_name)
中间涉及到的数据解析我们下个博客在介绍,这个例子主要是为了说一下ssl的情况
urlretrieve(url, filename=None, reporthook=None, data=None)
-
参数url:下载链接地址
-
参数filename:指定了保存本地路径(如果参数未指定,urllib会生成一个临时文件保存数据。)
-
参数reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕时会触发该回调,我们可以利用这个回调函数来显示当前的下载进度。
-
参数data:指post导服务器的数据,该方法返回一个包含两个元素的(filename, headers) 元组,filename 表示保存到本地的路径,header表示服务器的响应头
requests模块的介绍就到这里,其实request模块使用起来非常简便,困难的只是对网页的分析,所以大家在进行爬取工作之前能对web前端以及网络传输格式有个简单的了解。