查看原文
其他

如何批量采集网页表格数据?

大邓 大邓和他的Python 2022-07-09

本文的视频讲解已经上传到千聊平台 凡购买199元系列课的童鞋可直接免费观看学习

Comming Soon! Python&Stata数据分析课寒假工作坊

我们最想要的数据格式就是表数据,但这表格并不是excel文件,而是存在于网页上的表数据。比如本教程实验网站

http://s.askci.com/stock/a

一般遇到这种数据,最简单的方法就是复制粘贴,但是当

  • 复制粘贴格式混乱

  • 粘贴工作量太多 就需要写爬虫帮我们处理这件事情。但是常见的爬虫教程没有详细教大家怎么处理这种网址,今天我就简单说下办法。

审查网页

我们可以发现

  • 视图(平常肉眼所见)与html(图片下方的html)的一一对应对关系

  • html中有 <table>标签

网页种的table表

  1. <table class="..." id="...">

  2. <thead>

  3. <tr>

  4. <th>...</th>

  5. </tr>

  6. </thead>

  7. <tbody>

  8. <tr>

  9. <td>...</td>

  10. </tr>

  11. <tr>...</tr>

  12. <tr>...</tr>

  13. <tr>...</tr>

  14. <tr>...</tr>

  15. ...

  16. <tr>...</tr>

  17. <tr>...</tr>

  18. <tr>...</tr>

  19. <tr>...</tr>

  20. </tbody>

  21. </table>

先来简单解释一下上文出现的几种标签含义:

  • <table> : 定义表格

  • <thead> : 定义表格的页眉

  • <tbody> : 定义表格的主体

  • <tr> : 定义表格的行

  • <th> : 定义表格的表头

  • <td> : 定义表格单元

看到table这样的表格数据,我们可以利用pandas模块里的read_html函数方便快捷地抓取下来。

爬虫思路

  1. 寻找表格网页对应的url的网址规律

  2. 试图对某一个表格网页url进行访问

  3. 定位到所想要的table部分,得到 <table>...</table>字符串table_str

  4. 使用pd.readhtml(tablestr),得到一个df

  5. 循环2-4,得到的dfs(存放多个df的列表)

  6. 多个df合并为新的alldf(alldf为dataframe)结果保存到csv文件中, alldf.to_csv(filename)

实战

1. 网址规律

先尝试点击翻页,看看网址栏中url变化

我们很幸运的发现网址前后有变化

  1. http://s.askci.com/stock/a/0-0?reportTime=2019-09-30&pageNum=2#QueryCondition

  2. http://s.askci.com/stock/a/0-0?reportTime=2019-09-30&pageNum=3#QueryCondition

所以网址规律

  1. http://s.askci.com/stock/a/0-0?reportTime=2019-09-30&pageNum={pageNum}#QueryCondition

2. 尝试对任意页面(page2)进行访问

尝试对第二页进行访问,只要 肉眼见到html中的数据 对应上,就证明访问是正常的。

这里用 深圳市特力(集团)股份有限公司来验证

这次很幸运,因为requests.get(url)访问时并没有伪装成浏览器,网站也没有封锁这个python爬虫。我们继续

3. 定位table数据

如图,F12打开开发者工具, 我们定位到 id=myTable04的table。

  1. from bs4 import BeautifulSoup

  2. import pandas as pd


  3. bsObj = BeautifulSoup(resp.text)

  4. table = bsObj.find('table', {'id': 'myTable04'})

  5. table

Run

  1. <table cellpadding="0" cellspacing="0" class="fancyTable" id="myTable04">

  2. <thead>

  3. <tr>

  4. <th>序号</th>

  5. <th>股票代码</th>

  6. <th>股票简称</th>

  7. <th>公司名称</th>

  8. <th>省份</th>

3. table_str2dataframe

使用pd.readhtml(tablestr)将table字符串变为dataframe

  1. table_str = str(table)

  2. df = pd.read_html(table_str)

  3. df

Run

  1. [ 序号 股票代码 股票简称 公司名称 省份 城市 主营业务收入(201909) 净利润(201909) \

  2. 0 21 25 特力A 深圳市特力(集团)股份有限公司 深圳市 罗湖区 4.26亿 6541.11万

  3. 1 22 26 飞亚达A 飞亚达(集团)股份有限公司 深圳市 南山区 27.40亿 1.79亿

  4. 2 23 27 深圳能源 深圳能源集团股份有限公司 深圳市 福田区 157.80亿 19.40亿

  5. 3 24 28 国药一致 国药集团一致药业股份有限公司 深圳市 福田区 388.76亿 11.27亿

  6. 4 25 29 深深房A 深圳经济特区房地产(集团)股份有限公司 深圳市 罗湖区 19.03亿 4.40亿


  7. 员工人数 上市日期 招股书 公司财报 行业分类 \

  8. 0 337 1993-06-21 -- NaN 汽车销售

  9. 1 5162 1993-06-03 -- NaN 珠宝首饰

  10. 2 6649 1993-09-03 -- NaN 火电

  11. 3 24821 1993-08-09 -- NaN 医药商业

  12. 4 1954 1993-09-15 -- NaN 房地产开发


  13. 产品类型 \

  14. 0 主营业务:汽车销售、汽车检测维修及配件销售、物业租赁及服务

  15. 1 主营业务:主要从事钟表及其零配件的设计、开发、制造、销售和维修业务,包括"飞亚达"表的产品经...

  16. 2 主营业务:各种常规能源和新能源的开发、生产、购销,以及城市固体废物处理、城市燃气供应和废水处理等

  17. 3 主营业务:药品的研发、生产,中西成药、中药材、生物制品、生化药品、保健品、医疗器械的批发销售...

  18. 4 主营业务:商品住宅销售、物业租赁及管理服务、酒店客房服务,以及建筑安装装修服务。


  19. 主营业务

  20. 0 汽车销售、汽车检测维修及配件销售、物业租赁及服务

  21. 1 主要从事钟表及其零配件的设计、开发、制造、销售和维修业务,包括"飞亚达"表的产品经营和世界名...

  22. 2 各种常规能源和新能源的开发、生产、购销,以及城市固体废物处理、城市燃气供应和废水处理等

  23. 3 药品的研发、生产,中西成药、中药材、生物制品、生化药品、保健品、医疗器械的批发销售和连锁零售。

  24. 4 商品住宅销售、物业租赁及管理服务、酒店客房服务,以及建筑安装装修服务。 ]

跟我们设想的不太一样,结果不是dataframe应该有的样子。经过谷歌和百度,解决办法如下

  1. df = pd.read_html(str(table))[0]

  2. df.head()

4. 完整代码

重复操作

  1. 根据url规律,对多个表格url网页进行批量访问

  2. 重复之前对操作,得到dfs(存放多个df的列表)

  3. 将dfs转化为名为alldf的dataframe,并alldf.to_csv

  1. import requests

  2. import pandas as pd

  3. from bs4 import BeautifulSoup



  4. #伪装为浏览器

  5. headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"}



  6. #df列表容器,存放每个表格df

  7. dfs = []



  8. #一共有185个页面,这里仅仅就前10页进行测试

  9. template = 'http://s.askci.com/stock/a/0-0?reportTime=2019-09-30&pageNum={pageNum}#QueryCondition'

  10. for page in range(1, 11):

  11. print(page)

  12. url = template.format(pageNum=page)

  13. resp = requests.get(url, headers=headers)


  14. #定位table,得到table字符串

  15. bsObj = BeautifulSoup(resp.text)

  16. table_str = str(bsObj.find('table', {'id': 'myTable04'}))

  17. df = pd.read_html(table_str)[0]

  18. dfs.append(df)


  19. #将dfs转为alldf,注意dfs是列表,而alldf是dataframe

  20. alldf = pd.concat(dfs)

  21. #输出为csv

  22. alldf.to_csv('data.csv')

  1. 1

  2. 2

  3. 3

  4. 4

  5. 5

  6. 6

  7. 7

  8. 8

  9. 9

  10. 10

5. 采集结果

参数学习

  1. pandas.read_html(io,

  2. header=None,

  3. skiprows=None,

  4. attrs=None,

  5. parse_dates=False,

  6. encoding=None,

  7. converters=None)

常用的参数

  • io: 实际上io这个位置不仅可以是table字符串,还可以是表格的url、表格的html文本、或者本地文件等;但建议爬在本案例中用table_str而不是url。网址不接受https,尝试去掉s后爬去

  • header:标题所在的行数;

  • skiprows:跳过的行;

  • attrs:表格属性,对指定复合attrs值的表格进行解析,比如 attrs={‘id’:‘xxx’}解析id为xxx的table

  • parse_dates:是否解析日期,默认不解析

  • encoding: 文件编码格式,常见的有 utf-8、 gbk等,默认为None

  • converters: 字典格式,指定某一列按照某一类型数据去处理。如converters={'股票代码': str},对股票代码这一列按照字符串(而不是数字)方式处理


近期文章

精选课 | Python网络爬虫与文本数据分析(学术)

Python&Stata数据分析课寒假工作坊

用statsmodels库做计量分析

NRC词语情绪词典和词语色彩词典

Loughran&McDonald金融文本情感分析库

股评师分析报告文本情感分析预测股价

使用分析师报告中含有的情感信息预测上市公司股价变动

【公开视频课】Python语法快速入门

【公开视频课】Python爬虫快速入门

一行pandas代码生成哑变量

使用Python读取图片中的文本数据

代码不到40行的超燃动态排序图



课件获取方式,公众号后台回复关键词“20191229” 

如果想做文本分析

可购买网课 | Python文本数据分析实战(学术) 

或参加Python&Stata数据分析课寒假工作坊




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存