背景
暑假的钟声已敲响了一个星期有余了,这个星期也是有意放松一下自己,这段时间也在忙着各种各样的事情,都还是挺轻松的,那接下来的时间也要安排自己的学习计划了。学习网络爬虫的初衷是因为自己想爬取一下景点、酒店、饭店的评论信息,分析景点、酒店、饭店的口碑,接下来就是开启我的网络爬虫之旅。
爬虫简介
我是通过泰迪科技的网络爬虫教学视频进行学习的,个人觉得讲得知识点还是比较清晰的,但是内容质量如何,我也还不知道,但是在后续学别的爬虫课程我会继续将爬虫知识补充完整的。
网络爬虫就像一只蜘蛛一样在互联网上沿着URL的丝线爬行,下载每一个URL所指向的网页,分析页面内容。URL通俗来说就是网址。
先介绍robots协议,当一个爬虫爬取一个网站数据时候需要遵守网站所有者针对爬虫所制定的协议。robots协议通常是一个txt文本文件,里里面规定了此网站内容哪些可以被爬虫获取,及哪些网页时不允许爬虫获取的。
接着我们了解一下Python爬虫相关库:
网络前端基础
HTTP状态码
我们讲通俗一点,就是我们去爬取一个网站,首先需要发送请求到这个网站,那么网站就会返回状态码告诉你你的请求是否被通过,以及不能被通过的一些原因。我们常见的状态码格式:
http状态码共有67种,常见的状态码如下:
HTTP头部信息
HTTP头部信息是指在超文本传输协议的请求和响应消息中的消息头部分。
头部信息定义了一个超文本传输协议事务中的操作参数。在爬虫中需要使用头部信息向服务器发送模拟信息,通过发送模拟的头部信息将自己伪装成一般的客户端。
正则表达式
正则表达式是一种可以用于模式匹配和替换的工具,可以让用户通过使用一系列的特殊字符构建匹配模式,然后把匹配模式与待比较字符串或文件进行比较,根据比较对象中是否包含匹配模式,执行相应的程序。
正则表达式不难,而且这个工具很厉害,但是他的符号意义很多,而且答案不唯一,其中最难的地方就是挖掘模式共有的一个表达式。
举个简单的例子,我们有一串字符串:
txt = "王小二:13266778899;李老三:15931415926;赵四:13555489455;周五:13447589621
"
使用正则表达式将名字和手机号码分别提出来做成dataframe:
# 正则表达式的方法
import re #python处理正则表达式的库
import pandas as pd
#采用两种不同的方式获取手机号码
tels = re.findall( '\d{11}', txt ) # 该函数的返回值是所有电话号码的列表
print(tels) # \d 表示任意的一个阿拉伯数字, {11}表示重复11次
tels = re.findall( '[0-9]{11}', txt ) # 该函数的返回值是所有电话号码的列表
print(tels)
names = re.findall( '[\u4E00-\u9FA5]{2,4}', txt ) # 2--4个汉字
print(names)
pd.DataFrame({'Names': names, 'TelPhone': tels})
使用正则表达式获取网页标题
我们进行一个简单的实验,使用正则表达式爬取静态的网页中的标题,所谓静态就是我们爬取内容限制在这个网页的源代码。我们爬取北京理工大学珠海学院官网中的标题。
第一步:发送请求,解析网页
import requests
import re
url = 'http://www.bitzh.edu.cn/'
rqq = requests.get(url)
print('响应码:', rqq.status_code) #查看响应码
rqq.encoding = 'gbk' #设置网页中文编码,设置和网页的一样,否则会乱码
rqq.text #解析网页
第二步,观察我们要提取的内容,使用正则表达式表达
re.findall('<li><a href="[a-z0-9.:/]+" target=".*"{0,1}>(.+)</a></li>', rqq.text)
这个正则表达式并没有完全将我们想法中的网页标题进行提取,因为我也没找到一个正确的表达式,这也正是正则表达式的难点。
正则表达式虽然是万能的,但他确实复杂。所以下面我们介绍另外一种方法。
使用xpath解析网页
XML路径语言(XML Path Language),它是一种基于XML的树状结构,在数据结构树中找寻节点,确定XML文档中某部分位置的语言。
这个节点是什么意思呢?在谷歌浏览器的开发者工具中,我们可以通过控制节点来展开节点下的内容,节点下面可能还会有节点。类如:
三角形就是控制节点是否展开。那么我们就是利用提取内容的节点路径来提取我们的目标内容的。同样,我们使用这个方法做提取网页的标题。
第一步,因为Xpath只能处理文档的DOM表现形式,所以我们在解析网页内容后需要利用lxml库转化形式。
import requests
from lxml import etree
url = 'http://www.bitzh.edu.cn/'
rqq = requests.get(url)
html = etree.HTML(rqq.content, etree.HTMLParser()) #转化为文档的DOM表现形式
print(html)
etree.tostring(html, encoding='gbk').decode('gbk') #展示
rqq.encoding = 'gbk'
rqq.text
第二步,将网页标题的路径找出来。
html.xpath('/html/body/div/div/ul/li/a/text()')
#html.xpath('//*[@class="menu"]/ul/li/a/text()') #更加简便的形式
其中text()
是为了将我们想要提取内容以列表的形式打印出来。通过结果我们可以知道用这个方法是很好的将我们想要的内容提取出来。
更加简便的方法,在谷歌开发者工具无需让我们自己找Xpath路径,我们只需要选中内容,就能copy它的Xpath。
使用Beautiful Soup解析网页
Beautiful Soup不仅支持Python标准库中的HTML解析器,还支持一些第三方的解析器,具体语法如下:
通常我们采用lxml的解析器。
tag对象
Tag对象为HTML文档中的标签,形如<title>The Dormouse’s story</title>“或”<p class=“title”><b>The Dormouse’s story</b></p>"等HTML标签再加上其中包含的内容便是Beautiful Soup中的Tag对象。
通过Tag的名称属性可以很方便的在文档树中获取需要的Tag对象,例如:soup.head、 soup.body、soup.li
,但是通过该方法只能获取文档树中第一个同名的Tag对象,而通过多次调用可获取某个Tag对象下的分支Tag对象。通过find_all方法可以获取文档树中的全部同名Tag对象。
Beautiful soup定义了很多搜索方法,其中常用的有find方法和find_all方法,两者的参数一致,区别为find_all方法的返回结果是值包含一个元素的列表,而find直接返回的是结果。find_all方法用于搜索文档树中的Tag非常方便,如:soup.find_all('li')
我们通过例子来具体看看Beautiful Soup是怎么爬取的。
import requests
from bs4 import BeautifulSoup
rqq = requests.get('http://www.bitzh.edu.cn/') #获得HTTP请求
soup = BeautifulSoup(rqq.content, 'lxml') #创建BeautifulSoup对象
通过soup.find_all('li')
就可以将所有
- 的tag对象找出来。
我们还可以通过下面的方法访问tag对象的属性,其中herf是网页的某一个超链接网址。 -
a = soup.link a.name a.attrs a['href']
a = soup.find_all('ul') #找tag对象对用的标签 for i in a[0].find_all('li'): #再下一个节点 print(i.string) #打印输出
第二种爬取形式:
soup.select('.menu > li') # 点表示class #soup.select('#menu > li') # #表示id [i.text for i in soup.select('.menu > ul > li')]
第三种爬取形式:
soup.select('body > div > div > ul > li > a')[0].string
同样使用select方法可以使用节点路劲表达来查找,同样在开发者工具能找的到。
看到这里,有兴趣的朋友可以尝试爬取以下微博的前十热点榜。我们下章见。