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
badacook
V2EX  ›  Python

爬虫过程中 DOM 对象的处理

  •  
  •   badacook · 2021-04-03 10:28:24 +08:00 · 3395 次点击
    这是一个创建于 1360 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在练习过程中 尝试对一个页面 table 信息进行收集,pandas 也可读取页面全部 table,但是想使用爬虫中 DOM 的 xpath 语法,对 DOM 节点元素进行筛选,也算是第一次练习,在获得 相应的 table 元素后,没有思路了,在 DOM 元素数组,string 、与 XML 或者 pandas 数据表之间 卡主了,想请教一下 下一步 如何优雅的处理,还望大家不吝赐教

    实例如下:
    import requests
    from lxml import etree

    url = 'http://baostock.com/baostock/index.php/Python_API%E6%96%87%E6%A1%A3'
    headers = {
    "User-Agent" : "Mozilla\/5.0 (Windows NT 10.0; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/78.0.3904.108 Safari\/537.36"}
    text = requests.post(url, headers=headers)
    dom = etree.HTML(text.text) #将 web 页面文本信息解析为 HTML 文档
    print(dom)
    #通过 xpath 语法筛选 DO 文档中感兴趣的元素 此处返回该 id 下子节点 caption 属性为"返回数据说明"的 table 元素数组
    tables = dom.xpath('//*[@id="mw-content-text"]/table[@caption="返回数据说明"]')
    #下面开始 tables 数组处理 table 数组
    for table in tables:
    print(type(table))
    print(etree.tostring(table))
    20 条回复    2021-04-06 10:57:04 +08:00
    demo06
        1
    demo06  
       2021-04-03 15:03:46 +08:00 via Android
    就我所了解,你这个 tables 还是个 element 对象,你调用的 entree.tostring 方法只是获取了 tables 的对象索引值,如果需要获取 tables 下的子 element 的内容可以用 xpth('.//a[class="className"]/text()'),如果获取节点属性值可以用 xpath('.//a/@attrName/text()')来获取,注意获取子标签下的其他标签时不能有 /table 不然会出错具体什么原因我给忘了,昨天才看完😂,随后我翻翻,还有就是 /text()是获取当前标签下的直属文本内容,//text()是获取当前标签下所有的文本内容,这块刚看完,不知道我理解的对不对
    demo06
        2
    demo06  
       2021-04-03 15:10:08 +08:00 via Android
    另外 xpth 最后获取的内容是个集合,如果只有一个值可以后缀[0]取集合第一个下标的值,如果你 xpath 写的不太准确的最后获取的值有多个的话,下标写几就是取第几个值
    milukun
        3
    milukun  
       2021-04-03 15:40:37 +08:00
    首先,这个 xpath 就是不对的
    //*[@id="mw-content-text"]/table[@caption="返回数据说明"]
    你可以在 F12 里面直接 crtl+F 查找里面直接输入 xpath 看看能不能查找得到,这里是支持 xpath 的
    milukun
        4
    milukun  
       2021-04-03 15:40:50 +08:00
    badacook
        5
    badacook  
    OP
       2021-04-03 16:04:08 +08:00
    @milukun 因为 有多个 caption="返回数据说明" d table,分别是 id="mw-content-text"元素的子元素,且互为不间断的兄弟元素,我有 F12 查看 其中一个元素 xpath 检索 //*[@id="mw-content-text"]/table[26]/caption,我只是在这个基础上改成查找 包含 caption 属性,且值为"返回数据说明" 的 table 元素
    badacook
        6
    badacook  
    OP
       2021-04-03 16:08:15 +08:00
    @demo06 非常感谢 能不能分享一下 python 处理 dom 文档对象的文章,没找到切合的实例
    misaka19000
        7
    misaka19000  
       2021-04-03 16:41:31 +08:00
    https://cuiqingcai.com/5545.html

    我每次写爬虫都照着这个写 xpath 的语法
    badacook
        8
    badacook  
    OP
       2021-04-03 16:48:20 +08:00
    @misaka19000 我感觉 我 xpath 没写错,我有参照 W3C xpath 语法来写,就是取到了 DOM 对象,如何还原表单,后续的处理,我看 pandas 的 read_html 其中带 attrs 参数,参数为字典格式,可获取特定属性的 table,我使用 attrs = {"caption":"返回数据说明"} 不带这个参数能获取所有 table,带了反而报错
    demo06
        9
    demo06  
       2021-04-03 17:49:11 +08:00 via Android
    @badacook 我看的是爬虫的这块视频,主要解析 html,刚好有讲 xpath,https://b23.tv/cplcyn
    你可以去 B 站看一下,不知道能不能满足你的需求
    badacook
        10
    badacook  
    OP
       2021-04-03 20:21:33 +08:00
    发现了自己的一个大错误,caption 作为 table 的标题,并不是 table 的属性,而是最近的子元素,那针对 caption 的 table 筛选,何种方法最便捷呢
    vngghgfjnff
        11
    vngghgfjnff  
       2021-04-03 21:36:10 +08:00
    等答案
    demo06
        12
    demo06  
       2021-04-04 12:57:07 +08:00 via Android
    你贴个 HTML 吧
    badacook
        13
    badacook  
    OP
       2021-04-04 14:38:01 +08:00
    @demo06 http://baostock.com/baostock/index.php/Python_API%E6%96%87%E6%A1%A3
    比如这个页面 我想取出 所有的 caption 为返回数据说明的 table,结合 pandas 处理 DataFrame 的能力
    我上面 实例 里面的 text = requests.post(url, headers=headers) 就是获取 HTML 页面的 text.text
    你也可以直接 打开这个页面 http://baostock.com/baostock/index.php/Python_API%E6%96%87%E6%A1%A3
    使用 F12 查看源码
    demo06
        14
    demo06  
       2021-04-05 13:04:15 +08:00
    @badacook tables=tree.xpath('//table[@class="wikitable"]/caption[contains(text(),"返回数据说明")]/..')
    for table in tables:
    print(etree.tostring(table, method='html', with_tail=False))
    demo06
        15
    demo06  
       2021-04-05 13:04:40 +08:00
    @badacook 这样改就 OK 了
    demo06
        16
    demo06  
       2021-04-05 13:08:21 +08:00
    @badacook 总结一下,用 xpath 获取 caption 包含 返回数据说明的子标签然后用 /.. 再获取他的父标签(我看了一下页面里面所有 table 的 class 都是 wikitable,用这种方法获取比较准确),然后 toString 后,获得的就是标准 table 表格
    demo06
        17
    demo06  
       2021-04-05 16:11:12 +08:00
    page = requests.post(url, headers=headers).text
    tree = etree.HTML(page)
    tables=tree.xpath('//table[@class="wikitable"]/caption[contains(text(),"返回数据说明")]/..')
    for table in tables:
    content=etree.tostring(table)
    # result.decode('utf-8')
    with open('./table.html','ab+') as fp:
    fp.write(content)
    print(content)
    badacook
        18
    badacook  
    OP
       2021-04-05 19:25:56 +08:00
    @demo06 非常感谢大神 xpath 语法真的很赞,这个语法我要好好研究一下,本来还觉得学了解 xpath,自惭形秽啊
    demo06
        19
    demo06  
       2021-04-05 22:34:12 +08:00 via Android
    @badacook 能帮到你就好,我也就刚好看过这块内容😂
    zpfhbyx
        20
    zpfhbyx  
       2021-04-06 10:57:04 +08:00
    上 pyquery 吧。比这个省事。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3256 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:28 · PVG 20:28 · LAX 04:28 · JFK 07:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.