各位大佬有什么好的办法解析网页中不规整的表格吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
MrhuangSTR
V2EX    Python

各位大佬有什么好的办法解析网页中不规整的表格吗

  •  
  •   MrhuangSTR 2020-02-20 15:43:12 +08:00 4518 次点击
    这是一个创建于 2060 天前的主题,其中的信息可能已经有所发展或是发生改变。

    像几乘几这种规整的表格到很好解析,xpath 或者 bs4 或者 pandas 的 read_html 可以搞定,但是遇到那种不规整的表格,而且整个网站的表格样式可能都不一样,有什么好的办法做到通用解析,例如这个网站的表格

    第 1 条附言    2020-02-20 18:10:49 +08:00
    **表格是这个网站里的每条公告里的表格**
    36 条回复    2020-05-26 10:32:59 +08:00
    MrhuangSTR
        1
    MrhuangSTR  
    OP
       2020-02-20 17:52:54 +08:00
    大佬在哪里 f(;д`)
    akira
        2
    akira  
       2020-02-20 17:59:52 +08:00
    这个不是表格吧。。。
    deplives
        3
    deplives  
       2020-02-20 18:05:38 +08:00
    这哪里有表格?
    qazwsxkevin
        4
    qazwsxkevin  
       2020-02-20 18:06:29 +08:00
    依然用 for bs4 吧
    每个 div 下面有 ul
    每个 ul 下面有 5 个 li
    很明显的特征,性能不好的写法是嗦写多几个字典,逐个判断,逐个加
    不知道有无更好性能方法了
    MrhuangSTR
        5
    MrhuangSTR  
    OP
       2020-02-20 18:08:48 +08:00
    @akira 额 点进去每个公告里的表格
    MrhuangSTR
        6
    MrhuangSTR  
    OP
       2020-02-20 18:09:26 +08:00
    @deplives 每个公告的表格。。
    MrhuangSTR
        7
    MrhuangSTR  
    OP
       2020-02-20 18:09:36 +08:00
    @qazwsxkevin 公告里的表格。。
    qazwsxkevin
        8
    qazwsxkevin  
       2020-02-20 18:18:31 +08:00
    @MrhuangSTR 我能想到的是找出这个表格的 table 标签,然后对每个 tr 段,再对每个 td 做 get_text()了
    然后再洗数据加进字典
    就看了几个页面,似乎都差不多格式
    deplives
        9
    deplives  
       2020-02-20 18:18:41 +08:00
    @MrhuangSTR 请善用浏览器调试功能
    ![]( )
    superrichman
        10
    superrichman  
       2020-02-20 18:24:24 +08:00 via iPhone
    这种不规则的表格没有通用的解析方法,自己一个一个遍历元素取数据吧。还有这是个 gov 网站,如果你是想做爬虫的话,小心点别变成了 ddos 攻击 zf 网站。 /doge
    MrhuangSTR
        11
    MrhuangSTR  
    OP
       2020-02-20 18:26:36 +08:00
    @qazwsxkevin 每个栏目下分页基本上都有 120 页,可能前 1 到 20 页里的公告表格样式基本一致,某个区间段的表格格式又是另外一种,我现在大概看了下有 4 种不一样的表格,可能还有更多种。
    MrhuangSTR
        12
    MrhuangSTR  
    OP
       2020-02-20 18:27:32 +08:00
    @deplives 没这么简单的,多点开几个表格看看你会发现惊喜的 /doge
    MrhuangSTR
        13
    MrhuangSTR  
    OP
       2020-02-20 18:28:48 +08:00
    @superrichman 我 ip 今天就被 ban 了。。。。我都是很佛系的抓
    autoxbc
        14
    autoxbc  
       2020-02-20 18:44:41 +08:00
    都是很标准的表格,看不出有什么问题,最多有跨单元属性 colSpan 和 rowSpan,也是 html 标准之中的
    L2AKnG8GXx60bc6P
        15
    L2AKnG8GXx60bc6P  
       2020-02-20 19:09:28 +08:00 via iPhone
    我做过
    MrhuangSTR
        16
    MrhuangSTR  
    OP
       2020-02-20 21:08:29 +08:00
    @autoxbc 表格没啥问题,棘手的是怎么写一个通用的方法解析整站不同样式的表格
    MrhuangSTR
        17
    MrhuangSTR  
    OP
       2020-02-20 21:08:47 +08:00
    @relic 有什么好的办法分享下呗大佬
    metamask
        18
    metamask  
       2020-02-20 21:19:22 +08:00
    应该是没有通解办法,

    用 table 做的时候,他们都是直接怼进去 td 里面。

    有个办法你可以尝试下, 你先做一个判断是不是标题的函数, 然后扔进去解解看。
    比如最后带 ":" 判断为 label。

    但实话说,我觉得这个很难洗干净,至少不是一下子能洗干净。
    metamask
        19
    metamask  
       2020-02-20 21:23:19 +08:00
    但这类垂直爬取 有一个好处

    你可以自己先拿几个 做个处理就干净很多。
    比如你判断 “面积” 为 label 的时候,通过对比,知道一般他是在下一个 tr 里面,你写 parse 的时候,就把 2 个 tr 合起来,
    直接默认拿 tr_1.td_1: tr_2.td_1, tr_2: td_2
    metamask
        20
    metamask  
       2020-02-20 21:32:37 +08:00
    这种要洗干净你可以这么做。

    先下下来,随便拿一个,把表格洗了,然后字段扔进去 mapping, 如
    {
    "面积": parse_rule_1,
    }

    parse_rule_1(table, td)
    td = td. next_tr.td[index]
    table.pop(td)

    最后如果 table 里面还有元素的话,那么就是有新的元素,直接报错。
    你再手动去处理下。
    wangyzj
        21
    wangyzj  
       2020-02-20 21:55:30 +08:00
    不得不说国土资源部的网站做的还是挺清秀的
    akira
        22
    akira  
       2020-02-20 22:27:48 +08:00
    不要管 trtd, 全部内容提取出来,然后再统一清洗
    encro
        23
    encro  
       2020-02-20 22:51:53 +08:00
    直接使用 xpath 或者 css 遍历,最简单网站了。
    encro
        24
    encro  
       2020-02-20 23:01:33 +08:00
    原来是表格啊。
    不太可能有通用的,因为表格就不规范。
    你只能根据不同类型自己去写解析程序了。

    提示下:
    table 的 tr 下是 td,td 有两个属性,rowspan 和 colspan,它们的值就是分析表格的关键。但是对于这种不规则的,只能自己写程序,看有多少种类型,就微调下吧。
    TimePPT
        25
    TimePPT  
    PRO
       2020-02-20 23:40:49 +08:00
    换个思路,全部抓图然后表格 ocr 接口识别
    locoz
        26
    locoz  
       2020-02-20 23:42:23 +08:00
    无解。先拿下来再处理吧,按特征分成一类一类地处理,慢慢的就处理完了。
    然后建议用 GUI 标记工具(指类似于 pyspider、各种傻瓜式爬虫工具的点页面元素自动输出 xpath 到对应采集字段上的)辅助,要不然手写 xpath 很蛋疼。
    MrhuangSTR
        27
    MrhuangSTR  
    OP
       2020-02-21 10:18:14 +08:00
    @freakxx 标题有的带冒号有的不带。。
    另外你举的这个面积的例子,烦就烦在可能在其他表格里它对应的值就和它在一个 tr 里而不是下一个 tr;
    后面你说的这个方法应该是在已经确定需要哪些字段的情况下再去 mapping
    MrhuangSTR
        28
    MrhuangSTR  
    OP
       2020-02-21 10:18:45 +08:00
    @akira 清洗规则很难定
    MrhuangSTR
        29
    MrhuangSTR  
    OP
       2020-02-21 10:26:27 +08:00
    @locoz 这里的 xpath 倒不是很杂,看来只能分多种情况了
    hitaoguo
        30
    hitaoguo  
       2020-02-21 10:46:20 +08:00
    建议楼主贴几个不同类型的表格网址出来。
    metamask
        31
    metamask  
       2020-02-21 11:04:06 +08:00
    @MrhuangSTR

    你多抓几份看看就可以了,
    位置相对是固定的。

    你事先做一份已经确定不就好?如果没 map 到,再手动补上去,这个工作总能完成的。
    MrhuangSTR
        32
    MrhuangSTR  
    OP
       2020-02-21 18:44:03 +08:00
    @freakxx 这是个体力活啊,终于是搞定了。。
    Skyline57
        33
    Skyline57  
       2020-05-19 18:36:36 +08:00
    @MrhuangSTR 同病相怜啊楼主,我最近也是在搞这些 ZF 的数据,不过我好像解决了,找到了一种通用的方式
    我用的 xpath ( xpath 还是挺好使的),把键和值分开来获取,最后再 zip 到一起
    原理是:td 位置为奇数则是键,为偶数则是值
    (键为土地编号、面积等,值为据图数值)
    获取键的表达式:"//table//table//td[position() mod 2 = 1]"
    获取值的表达式:"//table//table//td[position() mod 2 = 0]"

    但是,提取之后会发现有的键是没有对应值的(比如“主要用途”那栏的值是空的)
    这时就要把没有对应值的键单独提出来
    观察几个网站发现没有对应值的键的相似之处为:都有 colspan="3"或者 colspan="6"的属性

    所以
    提取的 xpath 表达式为:'//table//table//td[position() mod 2 = 1][@colspan="3" or @colspan="6"]'

    最后把没有对应值的键都从所有键中剔除或者设为空,其他键值对一一对应即可

    .......
    .......

    最后发现出了点小问题

    呃呃呃,:面积"那栏键值是竖着的,不是向其他的那样横着的,也就是上述的最终键值对被污染了
    但是对"面积"这对键值单独处理下,应该问题不大,思路是用 xpath 获取到 text()为"面积"的 td 节点,再通过这个节点的父级 tr 的下一位置 tr 下的 td 获取到面积的数值,再从键列表中删除"面积",值列表中删除面积的值

    最后终于大功告成
    MrhuangSTR
        34
    MrhuangSTR  
    OP
       2020-05-25 16:01:20 +08:00
    @Skyline57 我跟你的解析思路一样的,花了我一天的时间,这玩意太折磨人了
    Skyline57
        35
    Skyline57  
       2020-05-25 17:19:43 +08:00
    @MrhuangSTR 我还遇到过一个网页里两三种编码的,真是吐了
    MrhuangSTR
        36
    MrhuangSTR  
    OP
       2020-05-26 10:32:59 +08:00
    @Skyline57 编码还好吧,一个网页有几种非常规的字体的你遇到过吗 ̄へ ̄
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5184 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 09:30 PVG 17:30 LAX 02:30 JFK 05:30
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86