likes
comments
collection
share

精通Python自动化脚本-运维人员宝典第十六章 网络抓取 - 从网站上提取有用的信息

作者站长头像
站长
· 阅读数 20

本章中我们将学习网页抓取的相关知识。我将还将学习Python中用于从网站上提取信息的beautifulsoup库。

本章主要涉及如下课题:

  • 什么是网页抓取?
  • 数据提取
  • 从维基百科提取信息

什么是网页抓取?

网页抓取是一种用于从网站上提取信息的技术。这一技术用于将非结构化数据转化为结构化数据。

网页抓取的用法是从网站是提取数据。提取的数据存储在本地系统的文件中,也可以存储在数据库的数据表中。网页抓取软件使用HTTP或浏览器直接访问万维网(WWW)。这是由网页爬虫或机器人实现的自动化过程。

爬取网页包含获取页面,然后提取数据。网页爬虫获取页面。爬虫是网页抓取中不可或缺的一个组件。在获取页面之后,就需要进行提取了。我们可以对页面进行搜索、解析、保存数据到数据表以及重构页面。

数据提取

这一部分,我们来看实际的数据提取过程。Python的beautifulsoup库可执行数据提取任务。我们还将使用Python的requests库。

首先,我们应安装这两个库。运行如下命令来安装requests和beautifulsoup库:

$ pip3 install requests
$ pip3 install beautifulsoup4

requests库

requests库的用处是以可读的格式使用Python脚本中的HTTP。我们可以在Python中使用requests库下载页面。requests库有不同的请求类型。这里我们将学习GET请求。GET请求用于从web服务器获取信息。web请求下载指定网页的HTML内容。每次请求都有一个状态码。状态码返回我们向服务器发送的每次请求。这些状态码向我们表明所做请求状况的信息。状态码的类型列举如下:

  • 200: 表明一切正常并在结果时返回结果
  • 301: 表明在域名切换或端点(endpoint)发生变化时服务器重定向到不同的端点
  • 400:表明请求有问题
  • 401: 表明请求未授权
  • 403: 表明在尝试访问禁止访问的资源
  • 404: 表明尝试访问的资源在服务器上不存在

beautifulsoup库

beautifulsoup是一个Python库,用于网页抓取。它带有搜索、导航、变更等简单易用的方法。是一个用于从网页上提取数据的工具集。

下面,要在我们的脚本中使用beautifulsoup的功能,需要使用import语句导入这两具库。我们将来看一个解析网页的示例。这里我们来解析一个IMDb网站的热门新闻面。创建一个脚本parse_web_page.py并在其中加入如下的内容:

import requests
from bs4 import BeautifulSoup

page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp')
parse_obj = BeautifulSoup(page_result.content, 'html.parser')

print(parse_obj)

运行脚本,我们将得到如下输出:

$ python3 parse_web_page.py

# 输出结果:
<!DOCTYPE html>

<html xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:og="http://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<meta content="app-id=342792525, app-argument=imdb:///?src=mdot" name="apple-itunes-app"/>
<script type="text/javascript">var IMDbTimer={starttime: new Date().getTime(),pt:'java'};</script>
<script>
    if (typeof uet == 'function') {
      uet("bb", "LoadTitle", {wb: 1});
    }
</script>
...
<div id="servertime" time="33"></div>
<script>
    if (typeof uet == 'function') {
      uet("be");
    }
</script>
</body>
</html>

上例中,我们获取了一个页面并使用beautifulsoup对其进行解析。首先我们导入了requests和beautifulsoup模块。然后,使用GET请求来获取 URL 并将该 URL 赋值给变量page_result。接着我们创建了beautifulsoup对象parse_obj。这一对象接收从requests获取的page_result.content作为参数,然后使用 html.parser对页面进行了解析。

下面我们将从class 和a标签中提取内容。要执行这一操作,打开浏览器并在想要提取的内容上右击,向下滚动可以看到Inspect(查看元素)的选项。点击它可以获取到class名。传入程序中并运行脚本。为此创建一个脚本extract_from_class.py并在其中编写如下内容:

import requests
from bs4 import BeautifulSoup

page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp')
parse_obj = BeautifulSoup(page_result.content, 'html.parser')

top_news = parse_obj.find(class_='news-article__content')
print(top_news)

运行脚本,我们将得到如下输出:

$ python3 extract_from_class.py
<div class="news-article__content">
                For a second weekend in a row <a href="/company/co0008970/">Disney</a> and <a href="/company/co0051941/">Marvel</a>'s <a href="/title/tt4154664/">Captain Marvel</a> topped the weekend box office as it has now posted over $760 million worldwide in just twelve days in global release. Overall, the weekend ended up topping the same weekend last year for a second straight week as both <a href="/title/tt6428676/">Wonder Park</a> and <a href="/title/tt6472976/">Five Feet Apart</a> outperformed expectations with their opening weekend performance. At the same time <a href="/company/co0173285/">Lionsgate</a>'s release of <a href="/company/co0325194/">Pantelion</a>'s <a href="/title/tt9019352/">No Manches Frida 2</a> delivered a top ten finish from just 472 theaters, topping Focus's disappointing release of <a href="/title/tt5968394/">Captive State</a>, which struggled in its debut in over 2,500 locations. Disney's <a href="/title/tt4154664/">Captain Marvel</a> topped the weekend box office for a second weekend in a row, delivering an estimated $69.3 million sophomore frame, dipping -54.8% and outperforming the -56% average second weekend dip for a film in the Marvel Cinematic Universe. This pushes the film's domestic cume over $266 million after just ten days in domestic release.
            </div>

上例中,首先我们导入了requests和beautifulsoup模块。然后,我们创建了一个请求对象并传入URL。接着,我们创建了一个beautifulsoup对象parse_obj。该对象从接收请求的page_result.content作为参数,并使用html.parser解析页面。然后我们使用了beautifulsoup的find()方法来从news-article__content这个 class中获取内容。

下面,我们来看一个从指定标签中提取内容的示例。在这个示例中,我们将从<a>标签中提取内容。创建一个脚本extract_from_tag.py并在其中编写如下内容:

import requests
from bs4 import BeautifulSoup

page_result = requests.get('https://www.imdb.com/news/top?ref_=nv_nw_tp')
parse_obj = BeautifulSoup(page_result.content, 'html.parser')

top_news = parse_obj.find(class_='news-article__content')
top_news_a_content = top_news.find_all('a')
print(top_news_a_content)

运行脚本,我们将得到如下输出:

$ python3 extract_from_tag.py
[<a href="/company/co0008970/">Disney</a>, <a href="/company/co0051941/">Marvel</a>, <a href="/title/tt4154664/">Captain Marvel</a>, <a href="/title/tt6428676/">Wonder Park</a>, <a href="/title/tt6472976/">Five Feet Apart</a>, <a href="/company/co0173285/">Lionsgate</a>, <a href="/company/co0325194/">Pantelion</a>, <a href="/title/tt9019352/">No Manches Frida 2</a>, <a href="/title/tt5968394/">Captive State</a>, <a href="/title/tt4154664/">Captain Marvel</a>]

上例中,我们从<a>标签中提取了内容。我们使用了find_all()方法来从news-article__content这个]()[class中提取了所有<a>标签中的内容。

从维基百科提取信息

这一部分中,我们将来看一个从维基百科获取舞蹈形式列表的示例。我们将列出所有的传统印度舞。创建一个脚本extract_from_wikipedia.py并在其中编写如下内容:

import requests
from bs4 import BeautifulSoup

page_result = requests.get('https://en.wikipedia.org/wiki/Portal:History')
parse_obj = BeautifulSoup(page_result.content, 'html.parser')

h_obj = parse_obj.find(class_='hlist noprint')
h_obj_a_content = h_obj.find_all('a')

print(h_obj)
print(h_obj_a_content)

运行脚本,输出内容如下:

$ python3 extract_from_wikipedia.py
<div class="hlist noprint" id="portals-browsebar" style="text-align: center;">
<dl><dt><a href="/wiki/Portal:Contents/Portals" title="Portal:Contents/Portals">Portal topics</a></dt>
<dd><a href="/wiki/Portal:Contents/Portals#Human_activities" title="Portal:Contents/Portals">Activities</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Culture_and_the_arts" title="Portal:Contents/Portals">Culture</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Geography_and_places" title="Portal:Contents/Portals">Geography</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Health_and_fitness" title="Portal:Contents/Portals">Health</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#History_and_events" title="Portal:Contents/Portals">History</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Mathematics_and_logic" title="Portal:Contents/Portals">Mathematics</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Natural_and_physical_sciences" title="Portal:Contents/Portals">Nature</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#People_and_self" title="Portal:Contents/Portals">People</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Philosophy_and_thinking" title="Portal:Contents/Portals">Philosophy</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Religion_and_belief_systems" title="Portal:Contents/Portals">Religion</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Society_and_social_sciences" title="Portal:Contents/Portals">Society</a></dd>
<dd><a href="/wiki/Portal:Contents/Portals#Technology_and_applied_sciences" title="Portal:Contents/Portals">Technology</a></dd>
<dd><a href="/wiki/Special:RandomInCategory/All_portals" title="Special:RandomInCategory/All portals">Random portal</a></dd></dl>
</div>
[<a href="/wiki/Portal:Contents/Portals" title="Portal:Contents/Portals">Portal topics</a>, <a href="/wiki/Portal:Contents/Portals#Human_activities" title="Portal:Contents/Portals">Activities</a>, <a href="/wiki/Portal:Contents/Portals#Culture_and_the_arts" title="Portal:Contents/Portals">Culture</a>, <a href="/wiki/Portal:Contents/Portals#Geography_and_places" title="Portal:Contents/Portals">Geography</a>, <a href="/wiki/Portal:Contents/Portals#Health_and_fitness" title="Portal:Contents/Portals">Health</a>, <a href="/wiki/Portal:Contents/Portals#History_and_events" title="Portal:Contents/Portals">History</a>, <a href="/wiki/Portal:Contents/Portals#Mathematics_and_logic" title="Portal:Contents/Portals">Mathematics</a>, <a href="/wiki/Portal:Contents/Portals#Natural_and_physical_sciences" title="Portal:Contents/Portals">Nature</a>, <a href="/wiki/Portal:Contents/Portals#People_and_self" title="Portal:Contents/Portals">People</a>, <a href="/wiki/Portal:Contents/Portals#Philosophy_and_thinking" title="Portal:Contents/Portals">Philosophy</a>, <a href="/wiki/Portal:Contents/Portals#Religion_and_belief_systems" title="Portal:Contents/Portals">Religion</a>, <a href="/wiki/Portal:Contents/Portals#Society_and_social_sciences" title="Portal:Contents/Portals">Society</a>, <a href="/wiki/Portal:Contents/Portals#Technology_and_applied_sciences" title="Portal:Contents/Portals">Technology</a>, <a href="/wiki/Special:RandomInCategory/All_portals" title="Special:RandomInCategory/All portals">Random portal</a>]

总结

本章中,我们学习了什么是网页抓取。还学习了两个用于从网页提取数据的库。同时从维基百科上提取了信息。

下一章中,我们将学习数据的收集和报表。我们将学习NumPy模块、数据可视化以及使用图表来展示数据。

课后问题

  1. 什么是网页抓取?
  2. 什么是网页爬虫?
  3. 你是否能在登录页后爬取数据?
  4. 你是否能爬取 Twitter?
  5. 是否是爬取 JavaScript 页面?若可以,如何爬取?

扩展阅读