常见的各种官网都有这样一种情况:
    
     网站中很多表格
    
    ,我们想对这些表格进行
    
     整理汇总
    
    、或者是
    
     筛选
    
    ,或者是
    
     处理分析
    
    。
   
    
     于是我们需要考虑:如何将网页表格数据使用python保存为Excel文件?
    
   
- 
     如果需要抓的表格很少或只需要抓一次,那么推荐
快速抓取法
[引文1]
。 - 
     如果页数比较多,推荐
完整爬虫抓取法
[引文2]
。解析函数用了BeautifulSoup和css选择器,这种方法定位提取表格所在的id为#myTable04的table代码段,更为准确。 
    
    
    0 基础知识
   
    
    
    table类型的表格网页结构
   
    一般情况下,网页的表格数据主要是在
    
     <table>
    
    标签中,
    
     <table>
    
    类型的表格网页结构大致如下:
   
<table class="..." id="...">
    <thead>
    <tr>
    <th>...</th>
    </tr>
    </thead>
    <tbody>
        <tr>
            <td>...</td>
        </tr>
        <tr>...</tr>
        <tr>...</tr>
        <tr>...</tr>
        <tr>...</tr>
        ...
        <tr>...</tr>
        <tr>...</tr>
        <tr>...</tr>
        <tr>...</tr>        
    </tbody>
</table>
简单解释上文出现的几种标签含义:
<table>	: 定义表格
<thead>	: 定义表格的页眉
<tbody>	: 定义表格的主体
<tr>	: 定义表格的行
<th>	: 定义表格的表头
<td>	: 定义表格单元
    使用pandas的
    
     read_html()
    
    方法就可以读取标签中的内容。
   
    
    
    read_html()函数
   
pandas.read_html(io,
				 match='.+', 
				 flavor=None, 
				 header=None,
				 index_col=None,
				 skiprows=None, 
				 attrs=None,
				 parse_dates=False,
				 tupleize_cols=None,
				 thousands=', ', 
				 encoding=None, 
				 decimal='.',
				 converters=None,
				 na_values=None,
				 keep_default_na=True,
				 displayed_only=True)
    
     常用的参数:
    
   
- io:可以是url、html文本、本地文件等
 - flavor:解析器;
 - header:标题行;
 - skiprows:跳过的行;
 - attrs:属性,比如 attrs = {‘id’: ‘table’};
 - parse_dates:解析日期
 
注意:返回的结果是
DataFrame
组成的
list
。
    
    
    1 快速抓取法
   
    
    
    1.1 思路
   
    这里以
    
     NBA Player Salaries – 2020-2021
    
    为例,具体步骤如下:
   
- 
     
step0:查看网页元素。
在目标网页中,右键“审查元素”,发现是
<table>
类型的网页结构,可以用
read_html()
抓取。
     - 
     
step1:确定抓取数据量和网页类型。
表数据共14页,数据量不大;且1-14页的网址只有page的变化,属于静态网页。 - 
     
step2:代码思路。
核心思路:使用pandas库中的
read_html()
函数,采用
快速抓取法
完成网页表格数据的收集。建立空白DataFrame结构 – 建立爬取网址合集urls – 依次爬取每一页的表格数据并append – 导出最终数据到csv。 
    
    
    1.2 代码
   
# 导入库
import pandas as pd
# 建立空白DataFrame
df=pd.DataFrame()
# 建立爬取网址合集urls
url_ori='http://www.espn.com/nba/salaries/_/page/'
urls=[url_ori+str(i) for i in range(1,15)]
# 依次爬取每一页的表格数据并append
for i,url in enumerate(urls):
    print(i+1)
    df=df.append(pd.read_html(url),ignore_index=True)
    
df.shape
    
# 数据筛选,ignore_index没有删除数据行中夹杂的标题行
df=df[df[0]!='RK'][[1,2,3]].reset_index(drop=True)
# 其他处理:
# df[1].apply(lambda x:x.split(',')[0])
# df[3].apply(lambda x:x[1:])
# 数据导出到CSV
df.to_csv(r'd:/desktop/NBA Player Salaries-2020-2021.csv',header=['NAME','TEAM','SALARY'],index=False)
    
   
    
    
    2 完整爬虫抓取法
   
    
    
    2.1 思路
   
    这里以
    
     中商情报网
    
    为例,具体步骤如下:
   
- 
step0:查看网页元素。
在目标网页中,右键“审查元素”,发现是
<table>
类型的网页结构,可以用
read_html()
抓取。
      - 
step1:确定抓取数据量和网页类型。
表数据共208页,数据量较大;且1-208页的网址只有pageNum的变化,属于静态网页。 - 
step2:代码思路。
核心思路:使用pandas库中的
read_html()
函数,采用
完整爬虫抓取法
完成网页表格数据的收集。将整个爬取分为网页提取、内容解析、数据存储等步骤,依次建立相应的函数 – 主函数建立空白DataFrame结构 – 依次爬取每一页的表格数据并append – 导出最终数据到csv。 
    
    
    2.2 代码
   
import pandas as pd
import requests
from bs4 import BeautifulSoup
from lxml import etree
from urllib.parse import urlencode  # 编码 URL 字符串
import time
start_time = time.time()  #计算程序运行时间
# 网页提取
def get_one_page(i):
    try:
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}
        paras = {
                    'reportTime': '2017-12-31',#可以改报告日期,比如2018-6-30获得的就是该季度的信息
                    'pageNum': i   #页码
                }
        # https://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=1
        # urlencode(paras)的值为:reportTime=2017-12-31&pageNum=1
        url = 'http://s.askci.com/stock/a/?' + urlencode(paras)
        response = requests.get(url,headers = headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        print('爬取失败')
        
# 内容解析
def parse_one_page(html):
    soup = BeautifulSoup(html,'lxml')
    content = soup.select('#myTable04')[0] #[0]将返回的list改为bs4类型
    tbl = pd.read_html(content.prettify(),header = 0)[0]# prettify()优化代码,[0]从pd.read_html返回的list中提取出DataFrame
    tbl.rename(columns = {'序号':'serial_number',
                          '股票代码':'stock_code', 
                          '股票简称':'stock_abbre', 
                          '公司名称':'company_name', 
                          '省份':'province', 
                          '城市':'city', 
                          '主营业务收入(201712)':'main_bussiness_income', 
                          '净利润(201712)':'net_profit', 
                          '员工人数':'employees', 
                          '上市日期':'listing_date', 
                          '招股书':'zhaogushu', 
                          '公司财报':'financial_report', 
                          '行业分类':'industry_classification', 
                          '产品类型':'industry_type', 
                          '主营业务':'main_business'},inplace = True)
    return tbl
    # tbl = pd.DataFrame(tbl,dtype = 'object') #dtype可统一修改列格式为文本
# 数据存储
def write_to_csv(df):
    df.to_csv(r'd:\desktop\test.csv',index=False)
# 主函数
def main(page):
    df=pd.DataFrame()
    for i in range(1,page):  
        html = get_one_page(i)
        tbl = parse_one_page(html)
        df=df.append(tbl)
    write_to_csv(df)
        
# 单进程
if __name__=='__main__':
    # 爬取前n=3页的数据
    n=3
    main(n+1)
    endtime = time.time()-start_time
    print('程序爬了{}页的表格数据,运行了{:.2f}秒'.format(n,endtime))
    
   
    
    
    3 小结
   
    最后,需说明
    
     不是所有表格都可以用这种方法爬取
    
    。
   
    比如这个网站中的表格,表面是看起来是表格,但在html中不是前面的
    
     table
    
    格式,而是
    
     list
    
    列表格式。这种表格则不适用
    
     read_html
    
    爬取。得用其他的方法,比如
    
     selenium
    
    。
    
    
   
引自:
[1]
关于python获取网页表格数据(read_html()方法)
[2]
利用pandas库中的read_html方法快速抓取网页中常见的表格型数据