所谓网络爬虫,通俗的讲,就是通过向我们需要的URL发出http请求,获取该URL对应的http报文主体内容,之后提取该报文主体中我们所需要的信息。所以,想要学习python爬虫,需要具备一些http的基础知识,熟悉http请求的基本过程。在本文中,首先会简单的介绍一下http请求的基本流程,之后介绍python的requests库,requests库可以方便地帮助我们完成http请求。因为本文介绍的是爬取静态网页,所以请求相应的URL之后,我们需要对其中的信息进行提取,这时候就需要BeautifulSoup库,它可以轻松的找出我们需要的信息,当然,有时候借助正则表达式会更快地帮助我们抽取网页中我们需要的信息。最后,我们会通过一个例子,对静态网页的爬取过程做一个具体的实现。
http基本知识
当我们通过浏览器访问指定的URL时,需要遵守http协议。本节将介绍一些关于http的基础知识。
http基本流程
我们打开一个网页的过程,就是一次http请求的过程。这个过程中,我们自己的主机充当着客户机的作用,而充当客户端的是浏览器。我们输入的URL对应着网络中某台服务器上面的资源,服务器接收到客户端发出的http请求之后,会给客户端一个响应,响应的内容就是请求的URL对应的内容,当客户端接收到服务器的响应时,我们就可以在浏览器上看见请求的信息了。这一过程如下图所示:
http请求过程.png
知道了http的基本请求过程,就可以通过代码进行体验了。
通过requests发起http请求
我们可以通过python的requests模块很方便的发起http请求。requests模块是第三方模块,安装完成之后直接import就能使用。下面介绍一些简单的用法,更多的使用方法可以参考如下链接:
requests
发起请求
import requests
# 请求的首部信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'
}
# 例子的url
url = 'https://voice.hupu.com/nba' # 虎扑nba新闻
# 利用requests对象的get方法,对指定的url发起请求
# 该方法会返回一个Response对象
res = requests.get(url, headers=headers)
# 通过Response对象的text方法获取网页的文本信息
print(res.text)
上面的代码中,我们向虎扑的服务器发送了一个get请求,获取虎扑首页的nba新闻。headers参数指的是http请求的首部信息,我们请求的url对应的资源是虎扑nba新闻的首页。获取到对应的网页资源之后,我们需要对其中的信息进行提取。
通过BeautifulSoup提取网页信息
BeautifulSoup库提供了很多解析html的方法,可以帮助我们很方便地提取我们需要的内容。我们这里说的BeautifulSoup指的是bs4。当我们成功抓取网页之后,就可以通过BeautifulSoup对象对网页内容进行解析。在BeautifulSoup中,我们最常用的方法就是find()方法和find_all()方法,借助于这两个方法,可以轻松地获取到我们需要的标签或者标签组。关于其他的方法,可以参考bs4的官方文档:BeautifulSoup
find()方法和find_all()方法的用法如下:
find(name , attrs , recursive , string , **kwargs )
# find_all()方法将返回文档中符合条件的所有tag,
find_all(name , attrs , recursive , string , **kwargs )
大多情况下我们只会用到前两个参数。具体用法如下:
from bs4 import BeautifulSoup
# BeautifulSoup对象接收html文档字符串
# lxml是html解析器
soup = Beautiful(res.text, 'lxml')
# 下面的方法找出了所有class为hello的span标签
# 并将所有的结果都放入一个list返回
tags = soup.find_all('span', {'class': 'hello'})
在我们真正开始爬虫的时候,还需要对网页的DOM结构进行分析,这样才能知道应该如何提取我们需要的信息,下面将会结合一个例子对DOM结构进行分析。
静态网页爬虫实战
在本节的例子里面,我们将对虎扑nba首页所有新闻的标题和来源进行爬取。首先我们导入我们所需要的requests和bs4模块,然后向目标url发出get请求获取首页的html文档。具体如下:
import requests
from bs4 import BeautifulSoup
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'
}
url = 'https://voice.hupu.com/nba' # 虎扑nba新闻
res = requests.get(url, headers=headers)
我们的目的是提取新闻的标题和来源,所以下一步需要对新闻首页的DOM结构进行分析。给出新闻首页的截图如下:
虎扑nba新闻首页.png
画红线的部分就是我们要爬取的信息,下面通过chrome控制台对DOM结构进行分析。结果如下图:
DOM分析结果.png
本着从特殊到一般的思路进行搜索,通过一个新闻信息进行分析,找出所有新闻的共性。通过分析发现,我们需要的标题信息是一个a标签对应的内容,然后我们需要向上进行搜索,可见标题信息的上一级是一个h4标签,h4标签的上一级是一个class属性值为list-hd的div标签,这个div的上一级是一个li标签。用通过同样的思路对来源信息进行分析,我们发现,新闻标题信息和新闻来源信息都在一个li标签下面,进一步可以发现,其他的新闻信息都在这类li标签下,这些li标签都在class属性值为news-list的div标签下,而且整片文档中,class属性值为news-list的div标签也只有这一个。
因此,我们可以从这个div入手,找到这个标签下的每一个li标签,对每一个li标签进行遍历,每一个li标签下有唯一的h4标签,该标签的文本即为我们要找的标题信息;另外,每一个li标签下也仅仅有一个class属性值为comeFrom的span标签,该span标签下的a标签对应的文本就是来源信息。分析结束之后,我们就可以通过bs4进行信息提取了。代码如下:
soup = BeautifulSoup(res.text, 'lxml')
# 找出class属性值为news-list的div
news_list = soup.find('div', {'class': 'news-list'})
# 找出news_list下的所有li标签
news = news_list.find_all('li')
news_titles = []
news_source = []
# 遍历news
for i in news:
try:
# 提取新闻标题
title = i.find('h4').get_text().strip()
# 提取新闻来源
source = i.find('span', {'class': 'comeFrom'}).find('a').get_text().strip()
# 存储爬取结果
news_titles.append(title)
news_source.append(source)
print('新闻标题:', title)
print('新闻来源:', source)
print()
except AttributeError as e:
continue
爬取结果如下图:
爬取结果.png
如有错误,还请指正