被恶心了很久了,写爬虫的遇到这种网页
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解析出来效果图:
# -*- 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