beautifulsoup爬取网页中的表格_用 Python 爬取网页

来自公众号:优达学城Udacity

作者:Kerry Parker

编译:欧剃

作为数据科学家的第一个任务,就是做网页爬取。那时候,我对使用代码从网站上获取数据这项技术完全一无所知,它偏偏又是最有逻辑性并且最容易获得的数据来源。在几次尝试之后,网页爬取对我来说就几乎是种本能行为了。如今,它更成为了我几乎每天都要用到的少数几个技术之一。

在今天的文章中,我将会用几个简单的例子,向大家展示如何爬取一个网站——比如从 Fast Track 上获取 2018 年 100 强企业的信息。用脚本将获取信息的过程自动化,不但能节省手动整理的时间,还能将所有企业数据整理在一个结构化的文件里,方便进一步分析查询。

太长不看版:如果你只是想要一个最基本的 Python 爬虫程序的示例代码,本文中所用到的全部代码都放在 GitHub (https://github.com/kaparker/tutorials/blob/master/pythonscraper/websitescrapefasttrack.py),欢迎自取。

准备工作

每一次打算用 Python 搞点什么的时候,你问的第一个问题应该是:“我需要用到什么库”。

网页爬取方面,有好几个不同的库可以用,包括:

  • Beautiful Soup

  • Requests

  • Scrapy

  • Selenium

今天我们打算用 Beautiful Soup 库。你只需要用 pip(Python包管理工具)就能很方便地将它装到电脑上:

2b4745ea17380028e206b534fac0357d.png

安装完毕之后,我们就可以开始啦!

检查网页

为了明确要抓取网页中的什么元素,你需要先检查一下网页的结构。

以 Tech Track 100强企业(https://link.zhihu.com/?target=http%3A//www.fasttrack.co.uk/league-tables/tech-track-100/league-table/) 这个页面为例,你在表格上点右键,选择“检查”。在弹出的“开发者工具”中,我们就能看到页面中的每个元素,以及其中包含的内容。

da2aca353e5348b06d436eaafce1400f.png
2af1a24f2bef1bd2a2f36cc693136432.png

右键点击你想要查看的网页元素,选择“检查”,就能看到具体的 HTML 元素内容

既然数据都保存在表格里,那么只需要简单的几行代码就能直接获取到完整信息。如果你希望自己练习爬网页内容,这就是一个挺不错的范例。但请记住,实际情况往往不会这么简单。

这个例子里,所有的100个结果都包含在同一个页面中,还被  标签分隔成行。但实际抓取过程中,许多数据往往分布在多个不同的页面上,你需要调整每页显示的结果总数,或者遍历所有的页面,才能抓取到完整的数据。

在表格页面上,你可以看到一个包含了所有100条数据的表格,右键点击它,选择“检查”,你就能很容易地看到这个 HTML 表格的结构。包含内容的表格本体是在这样的标签里:

c01abe9f8401c5982d34a8b4dc59b704.png

每一行都是在一个  标签里,也就是我们不需要太复杂的代码,只需要一个循环,就能读取到所有的表格数据,并保存到文件里。

附注:你还可以通过检查当前页面是否发送了 HTTP GET 请求,并获取这个请求的返回值,来获取显示在页面上的信息。因为 HTTP GET 请求经常能返回已经结构化的数据,比如 JSON 或者 XML 格式的数据,方便后续处理。你可以在开发者工具里点击 Network 分类(有必要的话可以仅查看其中的 XHR 标签的内容)。这时你可以刷新一下页面,于是所有在页面上载入的请求和返回的内容都会在 Network 中列出。此外,你还可以用某种 REST 客户端(比如 Insomnia)来发起请求,并输出返回值。
6c16c3bbcc3dfd6cfedc82c4e8b95e31.png
刷新页面后,Network 标签页的内容更新了

用 Beautiful Soup 库处理网页的 HTML 内容

在熟悉了网页的结构,了解了需要抓取的内容之后,我们终于要拿起代码开工啦~

首先要做的是导入代码中需要用到的各种模块。上面我们已经提到过 BeautifulSoup,这个模块可以帮我们处理 HTML 结构。接下来要导入的模块还有 urllib,它负责连接到目标地址,并获取网页内容。最后,我们需要能把数据写入 CSV 文件,保存在本地硬盘上的功能,所以我们要导入 csv库。当然这不是唯一的选择,如果你想要把数据保存成 json 文件,那相应的就需要导入 json 库。

3eed8fcd4fb7ebcd9d4d1a4598adec2b.png

下一步我们需要准备好需要爬取的目标网址。正如上面讨论过的,这个网页上已经包含了所有我们需要的内容,所以我们只需要把完整的网址复制下来,赋值给变量就行了:

3c268339739ab410baec2fcfa77756c5.png

接下来,我们就可以用 urllib 连上这个URL,把内容保存在 page 变量里,然后用 BeautifulSoup 来处理页面,把处理结果存在 soup 变量里:

a18d86d16b5252bb5b63e3bde457c104.png

这时候,你可以试着把 soup 变量打印出来,看看里面已经处理过的 html 数据长什么样:

f28670a772229da06bba9d58ca000d85.png

如果变量内容是空的,或者返回了什么错误信息,则说明可能没有正确获取到网页数据。你也许需要用一些错误捕获代码,配合 urllib.error (https://docs.python.org/3/library/urllib.error.html)模块,来发现可能存在的问题。

查找 HTML 元素

既然所有的内容都在表格里(

 标签),我们可以在 soup 对象里搜索需要的表格,然后再用 find_all 方法,遍历表格中的每一行数据。

如果你试着打印出所有的行,那应该会有 101 行 —— 100 行内容,加上一行表头。

33e1225ed53d1d69c01e3e482fe0f215.png

看看打印出来的内容,如果没问题的话,我们就可以用一个循环来获取所有数据啦。

如果你打印出 soup 对象的前 2 行,你可以看到,每一行的结构是这样的:

309c0232fd194ce6dc9a4d4e4b2ba357.png

可以看到,表格中总共有 8 列,分别是 Rank(排名)、Company(公司)、Location(地址)、Year End(财年结束)、Annual Sales Rise(年度销售增长)、Latest Sales(本年度销售额)、Staff(员工数)和 Comments(备注)。

这些都是我们所需要的数据。

这样的结构在整个网页中都保持一致(不过在其他网站上可能就没这么简单了!),所以我们可以再次使用 find_all 方法,通过搜索  元素,逐行提取出数据,存储在变量中,方便之后写入 csv 或 json 文件。

循环遍历所有的元素并存储在变量中

在 Python 里,如果要处理大量数据,还需要写入文件,那列表对象是很有用的。我们可以先声明一个空列表,填入最初的表头(方便以后CSV文件使用),而之后的数据只需要调用列表对象的 append 方法即可。

801945224c076780efd2aa0ff2973535.png

这样就将打印出我们刚刚加到列表对象 rows 中的第一行表头。

你可能会注意到,我输入的表头中比网页上的表格多写了几个列名,比如 Webpage(网页)和 Description(描述),请仔细看看上面打印出的 soup 变量数据——第二行第二列的数据里,可不只有公司名字,还有公司的网址和简单描述。所以我们需要这些额外的列来存储这些数据。

下一步,我们遍历所有100行数据,提取内容,并保存到列表中。

循环读取数据的方法:

f170d668c303e905ef6834438bf85ff4.png

因为数据的第一行是 html 表格的表头,所以我们可以跳过不用读取它。因为表头用的是  标签,没有用  标签,所以我们只要简单地查询 标签内的数据,并且抛弃空值即可。

接着,我们将 data 的内容读取出来,赋值到变量中:

9f9cc86304c94ae642af88b590011675.png

如上面的代码所示,我们按顺序将 8 个列里的内容,存储到 8 个变量中。当然,有些数据的内容还需有额外的清理,去除多余的字符,导出所需的数据。

数据清理

如果我们打印出 company 变量的内容,就能发现,它不但包含了公司名称,还包括和描述。如果我们打印出 sales 变量的内容,就能发现它还包括一些备注符号等需要清除的字符。

6e00bc541c4ff9c78dabe56045cf5408.png

我们希望把 company 变量的内容分割成公司名称和描述两部分。这用几行代码就能搞定。再看看对应的 html 代码,你会发现这个单元格里还有一个  元素,这个元素里只有公司名称。另外,还有一个  链接元素,包含一个指向该公司详情页面的链接。我们一会也会用到它!

f8b2c9496608153373cfb3fc46f44b67.png

为了区分公司名称和描述两个字段,我们再用 find 方法把  元素里的内容读取出来,然后删掉或替换 company 变量中的对应内容,这样变量里就只会留下描述了。

要删除 sales 变量中的多余字符,我们用一次 strip 方法即可。

9649dce06161772ed72f2a61523861cb.png

最后我们要保存的是公司网站的链接。就像上面说的,第二列中有一个指向该公司详情页面的链接。每一个公司的详情页都有一个表格,大部分情况下,表格里都有一个公司网站的链接。

e3107ea314a40bb84e76fd8718f01895.png

检查公司详情页里,表格中的链接

为了抓取每个表格中的网址,并保存到变量里,我们需要执行以下几个步骤:

在最初的 fast track 网页上,找到需要访问的公司详情页的链接。

发起一个对公司详情页链接的请求

用 Beautifulsoup 处理一下获得的 html 数据

找到需要的链接元素

正如上面的截图那样,看过几个公司详情页之后,你就会发现,公司的网址基本上就在表格的最后一行。所以我们可以在表格的最后一行里找  元素。

190b7ad7d6da8b252bb15c7a7262d5e3.png

同样,有可能出现最后一行没有链接的情况。所以我们增加了 try... except 语句,如果没有发现网址,则将变量设置成 None。当我们把所有需要的数据都存在变量中的以后(还在循环体内部),我们可以把所有变量整合成一个列表,再把这个列表 append 到上面我们初始化的 rows 对象的末尾。

4381d1f3dfd826b84ee1f2a12582276f.png

上面代码的最后,我们在结束循环体之后打印了一下 rows 的内容,这样你可以在把数据写入文件前,再检查一下。

写入外部文件

最后,我们把上面获取的数据写入外部文件,方便之后的分析处理。在 Python 里,我们只需要简单的几行代码,就可以把列表对象保存成文件。

c355f564c7d5ccbc258270cca9b64098.png

最后我们来运行一下这个 python 代码,如果一切顺利,你就会发现一个包含了 100 行数据的 csv 文件出现在了目录中,你可以很容易地用 python 读取和处理它。

总结

这篇简单的 Python 教程中,我们一共采取了下面几个步骤,来爬取网页内容:

连接并获取一个网页的内容

用 BeautifulSoup 处理获得的 html 数据

在 soup 对象里循环搜索需要的 html 元素

进行简单的数据清理

把数据写入 csv 文件中

如果有什么没说清楚的,欢迎大家在下面留言,我会尽可能给大家解答的!

附: 本文全部代码(https://github.com/kaparker/tutorials/blob/master/pythonscraper/websitescrapefasttrack.py)

祝你的爬虫之旅有一个美好的开始!

编译来源: towardsdatascience.com

●输入m获取文章目录

推荐↓↓↓

d987dc7e13317e94b838cea692ad3460.png

人工智能与大数据技术

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中Runnable和Thread的区别

概述 Runnable 是接口。 Thread 是类,且实现了Runnable接口。 Thread部分源码 public class Threadimplements Runnable {private static class Caches{static final ConcurrentMap subclassAudits new ConcurrentHashMap();static final ReferenceQueue subcla…

python 神经网络工具_神经网络15分钟入门!使用python从零开始写一个两层神经网络...

本篇是该系列的第三篇,建议在阅读本篇文章之前先看前两篇文章。在本文中将使用python实现之前描述的两层神经网络,并完成所提出的“象限分类”的问题。需要注意的是,虽然标题叫做神经网络15分钟入门,但是到这篇文章,对…

12.3目录结构

目录结构 设计好目录结构 可读性高可维护性高比如一个Foo项目Foo/--- bin/--- foo--- foo/--- tests/--- _init__.py--- test_main.py--- init.py--- main.py---doc--- conf.py---abc.rst--- setup.py--- requirement.txt--- README简要解释一下: bin/:存放项目的一…

pyecharts添加文字_超燃的文字云效果,用Python就能轻松get!

本文转载自公众号:数据森麟(ID:shujusenlin)作者:叶庭云链接:https://blog.csdn.net/fyfugoyfa/ 01 / 词云图词云图是一种用来展现高频关键词的可视化表达,通过文字、色彩、图形的搭配,产生有冲击力地视觉效…

同步关键词synchronized

概述 synchronized是java中的一个关键字,也就是说是Java语言内置的特性。 synchronized( 一个任意的对象(锁) ){ 代码块中放操作共享数据的代码。 } public synchronized int getIndex() {return 1;}public static synchronized int getN…

python连接mysql用哪个模块_Python连接MySQL数据库之pymysql模块使用

Python3连接MySQL本文介绍Python3连接MySQL的第三方库--PyMySQL的基本使用。PyMySQL介绍PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。Django中也可以使用PyMySQL连接MySQL数据库。PyMySQL安装pip install pymysql连接数据…

mysql 创建视图 主键_MySQL数据库基础操作命令,本文助你更上一层楼!

今天介绍的是关于Mysql数据库一些操作的基础命令用户与权限创建用户mysql>create user test identified by BaC321#; 修改密码5.5版本及以前的命令mysql>set password for testpassowrd(!1A2#3); 5.6及以上命令mysql>update mysql.user set authentication_stringpass…

mysql 聚合函数 怎么用在条件里_MySql 中聚合函数增加条件表达式的方法

Mysql 与聚合函数在一起时候where条件和having条件的过滤时机where 在聚合之前过滤当一个查询包含了聚合函数及where条件&#xff0c;像这样的情况select max(cid) from t where t.id<999这时候会先进行过滤&#xff0c;然后再聚合。先过滤出ID《999的记录&#xff0c;再查找…

drbd(三):drbd的状态说明

1.几种获取状态信息的方法 drbd有很多获取信息的方式。在drbd84和之前的版本&#xff0c;大多都使用cat /proc/drbd来获取信息&#xff0c;多数情况下&#xff0c;这个文件展示的信息对于管理和维护drbd来说已经足够。 例如以下是drbd84上两个volume的节点状态信息&#xff1a;…

Lock的lock()方法

ReentrantLock是JDK唯一实现了Lock接口的类 lock() 是平常使用得最多的一个方法&#xff0c;就是用来获取锁。如果锁已被其他线程获取&#xff0c;则进行等待。 由于在前面讲到如果采用Lock&#xff0c;必须主动去释放锁&#xff0c;并且在发生异常时&#xff0c;不会自动释放锁…

Lock的tryLock()方法

概述 tryLock()方法是有返回值的&#xff0c;它表示用来尝试获取锁&#xff0c;如果获取成功&#xff0c;则返回true&#xff0c;如果获取失败&#xff08;即锁已被其他线程获取&#xff09;&#xff0c;则返回false&#xff0c;这个方法无论如何都会立即返回。在拿不到锁时不…

python requests库详解_python的requests库详解

快速上手迫不及待了吗&#xff1f;本页内容为如何入门 Requests 提供了很好的指引。其假设你已经安装了 Requests。如果还没有&#xff0c;去安装一节看看吧。首先&#xff0c;确认一下&#xff1a;Requests 已安装Requests 是最新的让我们从一些简单的示例开始吧。发送请求使用…

python QTreeWidgetItem下面有几个子tree_python-nlp ch1笔记:nlp的基础应用、高级应用、python优势、nltk环境搭建...

本帖是对(印度)Jalaj Thanaki作品《python自然语言处理》的翻译、缩减及改编~nlp的基础应用NLP是AI的子分支&#xff0c;其相关概念可以用于以下专家系统中&#xff1a;语音识别系统问答系统机器翻译文本摘要情感分析基于模板的聊天机器人文本分类主题分割nlp的高级应用理解自然…

C#使用ListView更新数据出现闪烁解决办法

C#使用ListView更新数据出现闪烁解决办法 在使用vs自动控件ListView控件时候&#xff0c;更新里面的部分代码时候出现闪烁的情况 如图&#xff1a; 解决以后&#xff1a; 解决办法使用双缓冲&#xff1a;添加新类继承ListView 对其重写 1 public class DoubleBufferListView : …

Lock的tryLock(long time, TimeUnit unit)方法

概述 tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的&#xff0c;只不过区别在于这个方法在拿不到锁时会等待一定的时间&#xff0c;在时间期限之内如果还拿不到锁&#xff0c;就返回false。如果一开始拿到锁或者在等待期间内拿到了锁&#xff0c;则返回true。…

python语音识别的第三方库_python标准库+内置函数+第三方库: 7.音频处理

python标准库内置函数第三方库 欲善其事&#xff0c;必先利其器 这其器必是python的标准库内置函数&#xff0c;话说许多第三方库&#xff0c; 也是对标准库的使用&#xff0c;进行封装&#xff0c;使得使用起来更方便。 这些库以使用场景来分类: 7、音频处理 音频处理主要适用…

SperingBoot+vue文件上传下载预览

上传文件&#xff1a; 前端&#xff1a; 整个过程&#xff0c;就是在使用FormData 添加 上File&#xff08;这个Blob&#xff09;&#xff0c;并且key要和后台的名字对应上在点击上传按钮开始上传之前&#xff0c;使用了URL.createObjectURL(File)创建blobUrl&#xff0c;给了…

keepalived脑裂问题查找

在自己环境做keepalivedredis实验时&#xff0c;当重启了备用redies机器后&#xff0c;发现两台redies主机都拿到了VIP [plain] view plaincopy [rootredis2 ~]# ip addr list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopbac…

python 多线程并行 矩阵乘法_python实现简单的并行矩阵乘法

python实现简单的并行矩阵乘法python实现简单的并行矩阵乘法本文采用的矩阵乘法方式是利用一个矩阵的行和二个矩阵的列相乘时不会互相影响。假设A(m,n)表示矩阵的m行&#xff0c;n列。那么C(m,m)A(m,n) * B(n,m) &#xff1a;计算C矩阵时候分解成&#xff1a;process-1&#xf…

停止Java线程,小心interrupt()方法

转自http://www.blogjava.NET/jinfeng_wang/archive/2008/04/27/196477.html ---------------------------------------------------------------------------------------------------- 程序是很简易的。然而&#xff0c;在编程人员面前&#xff0c;多线程呈现出了一组新的难…