[My Own Wheels]含有合并单元格的html读取代码

被恶心了很久了,写爬虫的遇到这种网页
http://www.quzgt.gov.cn/News/Newsjuti.aspx?artid=6577

在此感谢 浙江宇天科技股份有限公司 的某个领导,没你的指导我不会想到去这么折腾一下,虽然聊了一阵木有什么结果。

标题,单元格一下子横向合并,一下子竖向合并,直接用pandas的read_html读出来十分辣眼睛
read_html(io, match=’.+’, flavor=None, header=None, index_col=None, skiprows=None, attrs=None, parse_dates=False, tupleize_cols=False, thousands=’,’, encoding=None, decimal=’.’, converters=None, na_values=None, keep_default_na=True)
也可能是我不会用吧=。=
总之,我自己写了一段解析的代码,方便自己平时用
github地址(暂用公司账号):
https://github.com/start712/MyWheels
文章开头的网站,用table_tr_td解析出来效果图:
文章开头的网站,用table_tr_td解析出来效果图

# -*- coding:utf-8 -*-  
"""
--------------------------------
    @Author: Dyson
    @Contact: Weaver1990@163.com
    @file: html_table_reader.py
    @time: 2017/7/19 16:35
    @instruction: table_tr_td => 解析html中tabel>tr>td这种格式的表格
                  standardize => 将解析过存储在df中的表格按需求做DIY
--------------------------------
"""
import sys
import bs4
import pandas as pd
import numpy as np

sys.path.append(sys.prefix + "\\Lib\\MyWheels")
reload(sys)
sys.setdefaultencoding('utf8')

class html_table_reader(object):
    def __init__(self):
        pass

    def table_tr_td(self, e_table, fill_method = None):
        """
        :param e_table: bs4中的table元素
        :param fill_method : 参数与fillna()中的method相同,选择填充方式,否则用None
        :return:
        """
        if not (isinstance(e_table, bs4.element.Tag) or isinstance(e_table, bs4.BeautifulSoup)):
            e_table = bs4.BeautifulSoup(e_table, 'html.parser')

        # 搭建表格框架
        df0 = pd.DataFrame(e_table.find_all('tr'))
        df0[1] = df0[0].apply(lambda e:len(e.find_all('td')))
        col_count = max(df0[1])
        row_count = len(df0.index)
        df = pd.DataFrame(np.zeros([row_count, col_count]), dtype=int)

        # 根据网页中的表格,还原在dataframe中,有合并单元格现象的
        # 值填在第一个单元格中,其他的用None填充
        e_trs = df0[0].tolist()
        for r in xrange(row_count):
            row = e_trs[r]
            e_tds = row.find_all('td')
            i = 0
            has_colspan = False
            for c in xrange(col_count):
                if pd.isnull(df.iloc[r,c]):
                    continue
                e_td = e_tds[i]
                # 横向合并的单元格
                if e_td.has_attr('colspan'):
                    has_colspan = True
                    for j in xrange(1, int(e_td['colspan'])):
                        df.iloc[r, c + j] = None
                # 竖向合并的单元格
                if e_td.has_attr('rowspan'):
                    for j in xrange(1, int(e_td['rowspan'])):
                        df.iloc[r + j, c] = None
                df.iloc[r, c] = e_td.get_text(strip=True)
                i = i + 1
            if has_colspan and fill_method:
                df.iloc[r,:] = df.iloc[r,:].fillna(method = fill_method)

        return df

    def standardize(self, df, delimiter='/\n/', b0 = True):
        """将数据的标题与数据分离,将有合并单元的行合并"""
        if b0 and df.iloc[0,:].hasnans and df.iloc[1,:].hasnans:# 假设第一排数据行没有横向合并单元格
            df.iloc[0, :] = df.iloc[0, :].fillna(method='ffill') + (delimiter + df.iloc[1,:]).fillna('')
            df.columns = df.iloc[0]
            df.columns.name = None
            df = df.drop([0,1], axis=0)

        for r in xrange(df.shape[0]-1, 0, -1):
            if df.iloc[r,:].hasnans:
                df.iloc[r-1, :] = df.iloc[r-1, :] + (delimiter + df.iloc[r, :]).fillna('')
                df = df.drop(r,axis=0)

        df.index = range(len(df.index)) # 索引重新从0计算
        return df
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值