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 · 4145 次点击
    这是一个创建于 1744 天前的主题,其中的信息可能已经有所发展或是发生改变。

    像几乘几这种规整的表格到很好解析,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 有什么好的办法分享下呗大佬
    freakxx
        18
    freakxx  
       2020-02-20 21:19:22 +08:00
    应该是没有通解办法,

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

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

    但实话说,我觉得这个很难洗干净,至少不是一下子能洗干净。
    freakxx
        19
    freakxx  
       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
    freakxx
        20
    freakxx  
       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  
       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
    建议楼主贴几个不同类型的表格网址出来。
    freakxx
        31
    freakxx  
       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   ·   实用小工具   ·   1274 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 18:04 · PVG 02:04 · LAX 10:04 · JFK 13:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.