拒绝想当然,不看文档导致GNE 的隐秘 bug

简介: 拒绝想当然,不看文档导致GNE 的隐秘 bug

摄影:产品经理在杭州竟然还能吃到豌豆尖,kingname 激动得喝了一碗汤

GNE[1]上线 4 天,已经有很多朋友通过它来编写自己的新闻类网页通用爬虫。

今天有一个用户来跟我反馈,GNE 0.1.4 版本在提取澎湃新闻时,只能提取一小部分的内容。

一开始我以为是提取算法有问题,Debug 了半天,最后才发现,是新闻正文在预处理的时候,就被提前删除了!

为了解释这个问题,我们用一小段 HTML 代码来还原当时的场景:

h = '''
<html>
    <body>
        <div class="txt">
        第一行
        <p class="con" />
        第二行
        <p class="con" />
        第三行
        </div>
    </body>
</html>
'''

阅读过 GNE 源代码的朋友都知道,GNE 会在预处理阶段尽可能移除没什么用的 HTML 标签。例如上面这段代码中的两行<p class="con" />都属于会干扰提取结果,且对提取没有任何帮助的标签。

于是我们使用 lxml 库的方法来移除它:

from lxml.html import fromstring
selector = fromstring(h)
useless_list = selector.xpath('//p[@class="con"]')
for useless in useless_list:
    useless.getparent().remove(useless)

根据想当然的理论:

  1. 找到<p class="con" />标签
  2. 找到它的父标签
  3. 从父标签里面把这两个无效标签移除掉

整个过程看起来没有问题,并且预期移除以后的 HTML 应该是这样的:

h = '''
<html>
    <body>
        <div class="txt">
        第一行
        第二行
        第三行
        </div>
    </body>
</html>
'''

但实际上,现实情况与想当然的情况自然不一样。真正的输出结果如下图所示:

<div class="txt">这个标签下面的text()有三行,分别为第一行第二行第三行。但是使用上面的代码移除时,第二行第三行都一并被删除了。

这是因为,这就是ElementTree.remove这个方法的行为。它不仅会移除这个节点,还会移除这个节点父节点的 text()中,位于这个节点后面的所有内容。

所以,正常的做法应该是直接调用要被移除这个节点的.drop_tag()方法。我们修改一下上面的代码:

from lxml.html import fromstring
from html import unescape
from lxml.html import etree
h = '''
<html>
    <body>
        <div class="txt">
        第一行
        <p class="con" />
        第二行
        <p class="con" />
        第三行
        </div>
    </body>
</html>
'''
selector = fromstring(h)
useless_list = selector.xpath('//p[@class="con"]')
for useless in useless_list:
    useless.drop_tag()
print(unescape(etree.tostring(selector).decode()))

运行效果如下图所示。

成功达到了我们想要的目的。

GNE 已经更新了版本,修复了这个 bug。使用 GNE 的同学请升级到 0.1.5 以上版本:

pip install --upgrade gne
目录
相关文章
|
7月前
|
程序员
面试高频题:开发人员说不是bug,测试如何答复?
面试高频题:开发人员说不是bug,测试如何答复?
130 0
|
安全 搜索推荐
下载软件别再被套路!教你避开流氓下载器的坑!
安装之前,可以看到界面中明显的提示:“使用360安全导航”、“ABC看图”,这两处旁边还有复选框,细心的你肯定知道要把这两个复选框去掉。
190 0
下载软件别再被套路!教你避开流氓下载器的坑!
|
安全 网络协议 Java
【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变,小白也能看懂
经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0 版本也没有完全解决问题,然后进而继续发布了 2.16.0 版本。大家都以为2.16.0是最终终结版本了,没想到才过多久又爆雷,Log4j 2.17.0横空出世。
639 0
|
SQL JSON 安全
技术分享|记一次差点错过任意密码重置漏洞
技术分享|记一次差点错过任意密码重置漏洞
143 0
技术分享|记一次差点错过任意密码重置漏洞
|
开发框架 Java 测试技术
【测试基础】五、这样提bug单,开发小哥还会怼你么?
【测试基础】五、这样提bug单,开发小哥还会怼你么?
【测试基础】五、这样提bug单,开发小哥还会怼你么?
|
测试技术
软件测试面试题:软件缺陷(或者叫Bug)记录都包含了哪些内容?如何提交高质量的软件缺陷(Bug)记录?
软件测试面试题:软件缺陷(或者叫Bug)记录都包含了哪些内容?如何提交高质量的软件缺陷(Bug)记录?
351 0
萌新学习C++容易漏掉的知识点,看看你中招了没有(一)
萌新学习C++容易漏掉的知识点,看看你中招了没有(一)
萌新学习C++容易漏掉的知识点,看看你中招了没有(一)
|
编译器 C++
萌新学习C++容易漏掉的知识点看看你中招了没有(二)
萌新学习C++容易漏掉的知识点看看你中招了没有(二)
萌新学习C++容易漏掉的知识点看看你中招了没有(二)
|
算法 搜索推荐 程序员
再也不担心用不好二分法了,因为我找到了"作弊"的接口
导读:算法是程序的灵魂,而复杂度则是算法的核心指标之一。为了降低复杂度量级,可谓是令无数程序员绞尽脑汁、甚至是摧枯秀发。一般而言,若能实现对数阶的时间复杂度,算法效率往往就已经非常理想。而实现对数阶的常用思想莫过于二分。 二分常有,好用的二分并不常有。while条件是lo<hi还是lo<=hi?分支判断mid是+1还是-1还是仍然取值mid?最后return哪个值?如果目标序列不是严格递增又该怎么处理?想想都不禁让人敬而远之。幸运的是,在python语言中,已经内置了成熟的二分函数。
142 0
再也不担心用不好二分法了,因为我找到了"作弊"的接口