python基础爬虫学习之路(一)
本文主要记录爬虫学习所遇到的各种问题和所学习的各种技术,适用初学python而又想要做点小项目的同学。
在开始学习爬虫之前提醒一下大家,爬虫的学习最好是建立在对web知识有一定了解的同学,但是,即使对web知识一点都不知道也并不妨碍对爬虫的使用,因为爬虫所涉及到的web知识并不会太深(如果你只是做简单的爬虫的话),你完全可以在学习爬虫的过程中去理解web的运作流程。
一、什么是爬虫
爬虫,简单来说就是在模仿用户访问网页,只不过爬虫的访问网页的速度比普通的用户要快得多。很多情况下我们需要海量的数据来做数据分析,而我们需要的数据记录在同一个网站的不同的网页甚至不同的网站上,这个时候,普通用户想要通过一个网页一个网页浏览,然后复制粘贴去保存数据,对于几百条数据,这种方式还可以接受,但是如果对于几万条甚至更多的数据,这样的方式获取数据显然太慢了。通过爬虫技术,我们可以让计算机帮助我们快速访问这些网页并下载我们所需要的数据。
下面的内容我将从python爬虫中一些比较基础而重要的方面来介绍构造爬虫的完整过程。
二、 运行环境的配置
python 3.7(建议安装时将其添加到系统环境变量中)
所需要的第三方库:
URL处理类:requests、json、urllib
HTML处理类:re、bs4、lxml
三、一个简单爬虫的工作流程
对目标URL发送请求——获取对方服务器的响应内容——从响应的内容中获取所需要的数据——保存数据
在编写爬虫时我们将从这几个流程所实现的功能来组织代码。
1.向目标URL发送请求and获取服务器的响应内容
先上代码
import requests #导入requests库
url = "http://www.baidu.com" #目标URL
response = requests.get(url) #发送请求获取的响应并保存在response中
response.encoding = response.apparent_encoding
#对response的编码方式进行调整
html = response.text #获取response的文本并保存在变量html中
print(html) #打印出html查看文本内容
大家可以先运行上面的代码,然后再分析这6行代码的作用。一定要记住这六行代码,因为这是你访问一个网页的开始。
代码讲解:
python中的requests库负责了对URL的请求工作,因此爬虫中我们需要导入requests库(当然还有一些其他的比如urllib.request这种的,可以尝试着去学习,我最开始用的就是urllib库来访问网页的)。关于requests库的用法一时半会介绍不完,目前这个阶段只需要知道它的get方法会生成一个Requests对象和一个Response对象,也就是这里的response,具体的格式为:
r=requests.get(url,params=None,**kwargs)
这里一共有三部分:url字符串、params、控制访问的参数 **kwargs
url的含义不用多说;
params是一个附加的对url进行解释的参数。
举个例子,比如说我们使用百度的时候URL里面往往有很多参数,仔细观察URL的格式可以发现:
https://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB
在问号后面跟着的是一个附加参数,wd是参数名,等于号后面是参数的值,这个值是经过编码之后的,这种形式的编码有两种分别是:
中文的gbk(GB2312)编码: 一个汉字对应两组%xx,即%xx%xx
中文的UTF-8编码: 一个汉字对应三组%xx即%xx%xx%xx
这两种编码需要用urllib.request库中的quote和unquote方法去编码和解码感兴趣的话可以尝试对“爬虫”这个词进行两种形式的编码。
s = "爬虫"
ss = quote(s,encoding='utf-8')
sss = quote(s,encoding='gbk')
运行之后将其打印出来为:
print(ss)
%E7%88%AC%E8%99%AB
print(sss)
%C5%C0%B3%E6
所以对比上面链接上的编码之后发现,上面用的是UTF-8的编码
有点扯远了,上面的内容就是想告诉你,你在发送get请求的时候其实是可以在URL中附加一些参数的,可以看到这些参数的值完全暴露在URL上面,安全性可想而知(大家都不想把自己的个人信息暴露出来对吧)param是这个参数就是帮助你在发送get请求的时候附加一些类似上面的信息,我们简单的尝试一下。
首先我们先写好我们需要查询的关键字构成的字典
data = {'wd':'爬虫'}
注意别忘了我们之前的url是http://www.baidu.com,里面并没有查询串(就是后面那个s?)所以我们修改一下原来的url
url = "http://www.baidu.com/s?" #目标URL
接着我们带上params这个参数请求
response = requests.get(url,params=data,headers=headers)
你会发现返回的结果中会出现一些爬虫的字样,如果你不确定是不是成功地利用百度搜索了“爬虫”这个关键词你可以打印出响应的url
print(response.url)
运行结果为:http://www.baidu.com/swd=%E7%88%AC%E8%99%AB
以上就是第二个参数的作用。
第三个参数非常重要,是控制访问的参数一共有12个,这里介绍几个比较重要的:
1.header:字典类型,保存浏览器的头部信息,目的是将爬虫伪装成浏览器对网页进行访问
因为有的网站会检查访问源的头部信息,所以可以利用这个特性避开反爬虫,浏览头信息的查找方法很简单,比如我现在在使用谷歌浏览器访问一个网页,F12打开开发者界面,在网络(Network)选项卡中随便点一个响应文件查看它的Headers,里面有很多信息,我们直接找到它的请求头(Request Headers)中的用户代理(Users-Agent)为:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36。
我们将其写成字典的格式{键:值}也就是:
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'}
然后将其写到get方法的参数中
response = requests.get(url,headers=headers)
就可以将爬虫伪装成指定的浏览器对目标URL进行访问了。
2.proxies:字典类型,设定访问代理服务器,可以增加登录认证
要使用这个参数,你就必须获得一些代理IP,代理IP有收费的和不收费的两种,收费的更加稳定,当然你也可以从一些代理IP网站上去找一些免费的代理IP,同样是将其写成字典形式然后添加到get方法中即可。
接下来要说到Response对象的一些属性
比如说在代码中出现的有:
text属性:响应内容的字符串形式;
encoding属性:从响应内容的头部信息来推断编码形式;apparent_encoding属性: 从响应内容的内容信息来推断编码形式;
还有一些也非常重要的属性例如
status_code属性:http请求的返回状态,200表示连接成功,404表示连接失败;
content属性:HTTP响应内容的二进制形式;
headers属性:http响应内容的头部内容
有了上面的属性,我们可以将上面写的爬虫完善一下。想一下,如果你写的爬虫在发送请求尝试获取对方服务器的响应这一步就已经失败了,后面的工作还怎么继续进行下去呢?因此我们需要在它访问失败的时候打印信息告诉我们,,这就要用到上面的:status_code属性了。结合上面的我们总结出代码的几个要素:
1.目标URL
2.URL附加的参数(可选)
3.浏览器头部信息的修改(可选)
4.代理IP(可选)
5.发送请求语句(上面几个可选参数)
6.请求失败的处理语句
现在我们修改一下之前编写的代码:
import requests #导入requests库
url = "http://www.baidu.com/s?" #目标URL
headers = {'User-Agent':'Mozilla/5.0\
(Windows NT 10.0; Win64; x64)Apple\
WebKit/537.36 (KHTML, like Gecko)\
Chrome/77.0.3865.90 Safari/537.36'} #浏览器头信息
data = {'wd':'爬虫'}
proxies = {'https':'https://117.57.91.76'}
response = requests.get(url,params=data,headers=headers,proxies=proxies)
#发送请求获取的响应并保存在response中
if response.status_code == 200:
response.encoding = response.apparent_encoding #对response的编码方式进行调整
html = response.text #获取response的文本保存在变量html中
print(html) #打印出html查看文本内容
else:
print("访问失败!")
以上就完成了爬虫的第一个关键步骤:发送请求和获取响应
2.对获取的HTML页面进行关键信息的提取
这个时候你所需要处理的就是一个字符串而已。现在我们已经把HTML页面搞到手,这个页面中的信息很多,但我们只想要其中对我们来说有用的信息。
可以看到网页上有文字,有图片,还有链接,那么如何从一大堆的字符串中提取想要的内容呢?
这就要用到我们浏览器的开发者工具了。按F12打开开发者工具
现在我们来学习一下开发者工具(Debug)
先看第一排的Element,它对应的是网页中的源代码,胆我们光看着一堆代码无法对元素进行定位,所以需要用到第一排最左边的元素定位的箭头来帮助我们定位元素。具体的操作就是点击元素定位器,然后再页面上点你感兴趣的元素,可以是文本可以是图片可以是链接,点完之后你就会发现,文本会自动跳转到HTML中相应的位置,并用阴影给你标出来,不但如此,它的下方还会显示它的xpath
xpath表达式来定位元素的位置是非常方便又准确的,建议大家学习一下,这里我讲几个简单的写xpath表达式来定位元素的方法。
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。以下面的html为例
<html>
<body>
<title>information of A good person</title>
<person>YU Sir</person>
<age>20</age>
<div class = "job" href = "xxxxxxxx">
quite a good job!
<jobname>worker</jobname>
<jobtime>8hours</jobtime>
</div>
<div class = "addr" href = "000000000">good place</div>
</body>
</html>
<html> 是文档节点,<html>和</html>之间的元素是文档的内容,它是万物起源,也就是祖先的意思。
接着再它里面有一个<body>节点,可以看到<body>是<html>的唯一的后代。
然后看<body>里面一共有5个后代节点分别是<title><person><age><div><div>可以看出title、person、age这几个里面都有文本,比较特殊的是div节点,第一个div节点有两个后代节点,它们的节点中还都附带了class和href两个属性。
现在我们看看如何获取这些信息:
获取title里面的文本information of A good person:
/html/body/title/text()
获取div里面class的值job:
/html/body/div/@class/text()
获取div里面class值为job的链接
/html/body/div[@class=‘job’]/@href/text()
获取全部的div标签中的文本quite a good job!和good place
/html/body//div/text()
有了上面的基本的信息之后就可以帮助我们解决很多定位元素的问题,这里稍微讲解一下
/text() :获取这个标签下的文本,
/@属性名:定位到某个节点的属性
[查询串] :根据查询条件定位某个节点
经过简单地学习,就可以上手使用xpath表达式来定位所需要的元素了,在真正使用之前我们要确保lxml库已经完成安装并检查已安装地lxml库是否能够导入etree模块
from lxml import etree
完成了这步工作之后就可以开始使用了,要使用xpath表达式来查询我们需要把之前获得地html文本加工一下:
element = etree.HTML(html)
然后就可以使用xpath表达式进行查询了
result = element.xpath("xpath表达式") #查询结果返回的是一个列表
现在我们实操一下,比如说我们想获取之前百度搜索爬虫的网页的title
import requests #导入requests库
from lxml import etree
url = "http://www.baidu.com/s?" #目标URL
headers = {'User-Agent':'Mozilla/5.0\
(Windows NT 10.0; Win64; x64)Apple\
WebKit/537.36 (KHTML, like Gecko)\
Chrome/77.0.3865.90 Safari/537.36'} #浏览器头信息
proxies = {'https':'https://117.57.91.76'}
data = {'wd': '爬虫'}
response = requests.get(url,params=data,headers=headers,proxies=proxies)
#发送请求获取的响应并保存在response中
if response.status_code == 200:
response.encoding = response.apparent_encoding #对response的编码方式进行调整
html = response.text #获取response的文本保存在变量html中
else:
print("访问失败!")
element = etree.HTML(html) #要是用xpath表达式必须先将之前的字符串转化为元素树
result = element.xpath('/html/head/title/text()')
print(result)
运行结果为:
这样一个最简单的爬虫就诞生了,大家可能看着没什么用,但是千里之行,始于足下,更厉害的爬虫下期再更!