抓取网页生成电子书(目录各种尝试生成PDF提取文章内容选择文|李晓飞总结)
优采云 发布时间: 2022-02-14 18:04抓取网页生成电子书(目录各种尝试生成PDF提取文章内容选择文|李晓飞总结)
目录各种尝试生成PDF提取文章内容选择优化总结参考正文 | 李小飞来源:Python技术“ID:pythonall”爬虫程序大家一定不陌生,只要写一个就可以获取网页上的信息,甚至可以通过请求自...
目录选择最佳摘要参考
正文 | 李晓飞
来源:python科技《ID:pythonall》
爬虫程序想必大家都不陌生。您可以通过编写一个获取网页信息,甚至可以通过请求自动生成 Python 脚本 [1]。
最近在网上遇到一个爬虫项目,需要爬取文章。感觉没什么特别的,但问题是没有限制爬取范围,也就是说没有清晰的页面结构。
对于一个页面,除了核心的文章内容外,还有页眉、拖尾、左右列表栏等。有的页框使用div布局,有的使用table,即使使用了div,样式和网站 的布局不同。
但问题必须解决。我想,既然各种网页的核心内容都是搜索引擎抓取的,那我们应该也能做到,拿起Python,说到做到!
各种尝试
如何解决?
生成 PDF
我开始想一个比较棘手的方法,就是使用一个工具(wkhtmltopdf[2])从目标网页生成一个PDF文件。
好处是不用关心页面的具体形式,就像给页面拍照一样,文章结构就完整了。
虽然可以在源代码级别搜索 PDF,但生成 PDF 有很多缺点:
它消耗大量计算资源,效率低,错误率高,体积太大。
数万条数据已经超过200GB。如果数据量增加,只有存储将是一个大问题。
提取 文章 内容
有一种简单的方法可以通过 xpath[3] 提取页面上的所有文本,而不是生成 PDF。
但是内容会失去结构并且可读性降低。更糟糕的是,网页上有很多不相关的内容,比如侧边栏、广告、相关链接等,也会被提取出来,影响内容的准确性。
为了保证一定的结构和识别核心内容,只能识别和提取文章部分的结构。就像搜索引擎学习一样,就是想办法找出页面的核心内容。
我们知道,一般情况下,页面上的核心内容(比如文章部分)是比较集中的,我们可以从这个地方入手分析。
所以我写了一段代码。我使用 Scrapy[4] 作为爬虫框架。这里我只截取了提取 文章 部分的代码:
divs = response.xpath("body//div")
sel = None
maxvalue = 0
for d in divs:
ds = len(d.xpath(".//div"))
ps = len(d.xpath(".//p"))
value = ps - ds
if value > maxvalue:
sel = {
"node": d,
"value": value
}
maxvalue = value
print("".join(sel['node'].getall()))
简单明了,测试了几页确实不错。
但是,在大量提取过程中,发现很多页面无法提取数据。仔细观察会发现有两种情况。
再次调整策略,不再区分div,查看所有元素。
另外,p多是首选,在它的基础上看到的div少。调整后的代码如下:
divs = response.xpath("body//*")
sels = []
maxvalue = 0
for d in divs:
ds = len(d.xpath(".//div"))
ps = len(d.xpath(".//p"))
if ps >= maxvalue:
sel = {
"node": d,
"ps": ps,
"ds": ds
}
maxvalue = ps
sels.append(s编程客栈el)
sels.sort(lambda x: x.ds)
sel = sels[0]
print("".join(sel['node'].getall()))
经过这次修改,确实在一定程度上弥补了之前的问题,但是引入了一个比较麻烦的问题。
即发现的文章体是不稳定的,特别容易受到其他部分的一些p的影响。
选最好的
由于不适合直接计算,因此需要重新设计算法。
我发现文字集中的地方往往是文章的主体,而之前的方法没有考虑到这一点,只是机械地找了最大的p。
还有一点,网页结构是一棵DOM树[6]
那么离p标签越近的地方应该越有可能是文章主题,也就是说计算是离p越近的节点权重应该越大,离p越远的节点有一个很多 p 及时,但权重也应该更小。
经过反复试验,最终代码如下:
def find(node, sel):
value = 0
for n in node.xpath("*"):
if n.xpath("local-name()").get() == "p":
t = "".join([s.strip() for s in (n.xpath('text()').getall() + n.xpath("*/text()").getall())])
value += len(t)
else:
value += find(n, a)*0.5
if value > sel["value"]:
sel["node"] = node
sel["value"] = value
return value
sel = {
'value': 0,
'node': None
}
find(response.xpath("body"), sel)
经过这次改造,效果特别好。
为什么?其实就是利用了密度的原理,即越靠近中心,密度就越高,远离中心的地方密度呈指数下降,这样就可以把密度中心筛掉。
50%的斜率是怎么来的?
事实上,它是通过实验确定的。一开始我设置为90%,但是body节点最后总是最好的,因为body收录了所有的文本内容。
经过反复试验,确定 50% 是一个不错的值,如果不适合您的应用,请进行调整。
总结
在描述了我如何选择 文章 主题之后,我发现它实际上并不是一个非常简单的方法。而这次解题的经历,让我感受到了数学的魅力。
我一直认为,只要你理解了处理问题的常规方式,处理日常编程就足够了。当遇到不确定的问题,没有办法提取简单的模型时,常规思维显然是不够的。
因此,我们通常应该看一些数学强,解决不确定问题的方法,以提高我们的编程适应性,扩大我们的技能范围。
希望这篇短文能对你有所启发,欢迎在留言区交流讨论,对比你的心!
参考
[1]
卷曲到 Python:
[2]
wkhtmltopdf:
[3]
路径:
[4]
刮擦:
[5]
jQuery:
[6]
DOM 树:%20Tree/6067246