0

0

The Detail of Extracting & Curating Articles_html/css_WEB-ITnose

php中文网

php中文网

发布时间:2016-06-24 11:15:11

|

1459人浏览过

|

来源于php中文网

原创

The Detail of Extracting & Curating Articles

[TOC]

最近工作又涉及到Html 页面新闻正文提取的问题。有很多第三方Library 能解决这个问题,但是总有些功能还是不能满足,或者对中文不适用。所以本文将利用Newspaper,python-goose,python-readability 这几个包来解读以下新闻提取的一些细节,我是在阅读源代码所以会有一些其他编程技巧记录在里面,可能会显得混乱,如果只对解析新闻正文感兴趣你可以忽略。

相关 简介

  • Newspaper里面的代码我没觉得不怎么好,它核心的正文提取部分的实现借鉴了python-goose 可以说是相同的。实现了新闻抓取到解析的整个过程,提供,图片,视频,标题,正文,作者,时间等字段的提取。 主要使用了requests, beautifulSoup ,lxml 等包。可能是推广做得比较好三个包中间在GitHub上的Star它是做多的目前有3324个。reqeusts的作者还为它发了条 twitter。看到这么多star 也是我主要阅读的项目。 用法:
`from newspaper import Articleurl = 'http://www.cankaoxiaoxi.com/roll10/20160619/1197379.shtml'article = Article(url)article.download()article.parse()print(article.text)

` * python-goose最开始是一个Java项目,后来作者改为 Scala实现

立即学习前端免费学习笔记(深入)”;

。由于Newspaper的主要功能是借鉴了这个包,所以具体细节也只在Newspaper中介绍。这个包不支持Python3.x

  • python-readability这个包的的来历就更加复杂了,我现在用的是这个,由于部分功能不能满足我的需求,所以在此之上稍有增加一些其他的。 用法:
`from readability.readability import Documentimport urllibhtml = urllib.urlopen(url).read()readable_article = Document(html).summary()readable_title = Document(html).short_title()

`

对比

由于Newspaper parse()默认就会解析图片,视屏,如果在缺失一些视频,图片相关依赖的时候会报错,考虑的效率,对于图片,视屏这些不需要的功能应该分开会比较好,而不是默认解析所有。 python-readability就相对比较好一点。需要的时候才会解析。而且python-readability并不会帮我下载页面,这个也正好是我的需求。当然Newspaper 也支持传递html 但是感觉其实现很丑,真的很丑。 如果你不想自己实现,建议使用python-readability.

Newspaper 源码简析

代码结构

`├── api.py├── article.py                     所有的功能封装在这个里面├── cleaners.py                清洗HTML页面├── configuration.py         配置├── extractors.py              提取正文等核心功能实现├── images.py                 图片相关,这个我忽略不关心├── __init__.py├── mthreading.py          多线程模块,作者自己实现的线程尺用于HTML下载├── network.py                封装requests 下载HTML├── nlp.py                        简单自然语言处理功能比如关键词提取├── outputformatters.py   格式化输出├── parsers.py                 封装lxml,提供一些方便的方法├── resources                 存放数据文件<br />├── settings.py<br />├── source.py<br />├── text.py                     对词的处理,算分的时候会用到├── urls.py                     一些urls 的方法├── utils.py<br />├── version.py└── videos

` 代码里面的东西还是挺多的,支持很多种语言,忘了说中文还用到了jieba分词。顺着文档中给出的例子

download

这部分是使用了requests , 作者在此封装了一个多线程的功能下面把其中的线程池拿出来玩了下,是Python3实现,写了个测试的。 ```

from threading import Thread import queue import traceback

class Worker(Thread): def init(self, tasks, timeout seconds): Thread. init (self, ) print(self.getName()) self.tasks = tasks self.timeout = timeoutseconds self.daemon = True self.start()

def run(self):    while True:        try:            func, args, kargs = self.tasks.get(timeout=self.timeout)            print(":".join((self.getName(), args[0])))        except queue.Empty:            # Extra thread allocated, no job, exit gracefully            break        try:            func(*args, **kargs)        except Exception:            traceback.print_exc()        self.tasks.task_done()

class ThreadPool: def init(self, num threads, timeoutseconds): self.tasks = queue.Queue(num threads) for _ in range(numthreads): Worker(self.tasks, timeout_seconds)

def add_task(self, func, *args, **kargs):    self.tasks.put((func, args, kargs))def wait_completion(self):    self.tasks.join()

urls = [ 'http://www.baidu.com', 'http://midday.me', 'http://94fzb.com', 'http://jd.com', 'http://tianmao.com', ]

import requests import time

def task(url): return requests.get(url)

def test threadpool(): pool = ThreadPool(2, 10)

start = time.time()for url in urls:    pool.add_task(task, url)pool.wait_completion()print("threadpool spant: ", time.time() - start)

def test singlethread(): start = time.time() for url in urls: task(url) print("singlethread spent: ", time.time() - start)

if name== ' main':

test_single_thread()test_thread_pool()

```

正文提取

标题和作者的提取对我用处并不大,何况作者部分还只支持英文,看了下也是基于规则的,总的来说所有解析都是基于规则的。用到一些统计的方法,但根本上还是规则,肯定有不适用的时候。 正文的提取主要分下面几步:

大师兄智慧家政
大师兄智慧家政

58到家打造的AI智能营销工具

下载

1.清洗掉部分不需要的标签 2.计算获得包含正文内容的根节点 3.利用outpuformat 对第二步中选出的节点的文本输出

核心在第2步里面具体代码在extractors.py 的ContentExtractor 的calculate bestnode方法实现 第2步可以详细拆分:

1.选取所有p,pre,td 标签 2.清除连接密集型标签,这里会用到is highlinkdensity方法,如果满足下面这个公式: 所有a标签的词数/所有候选标签次数> 1/a标签总数 就认为是连接密集型,会被扔掉。 3.计算节点得分,分为两部分,一部分是包含的stopword的数量,在resource 文件夹下面有对应语言的词表,其实这个词表不是黑名单,更像是白名单。还有一部分叫boost score。 boostscore 这个分数是对文章开头和结尾部分的标签的不同处理,开头的段会获得较多的加分,当候选节点多余15个,最后4分之一的节点都会得到更少的分数(作者解释是可能会是评论) 。

`boost_score = float((1.0 / starting_boost) * 50)

` 上面是根据段的顺序的加分公式,starting_boost 会不断递增,当然还有一个判断节点是不是boost 。逻辑就是判断是否为p标签,包含的stopwords 大于5个(这个是很费解的)。中文的, stopwords, 存在stopwords-zh.txt中我看了下都是些常用词,只有125个(这个怎么来的,并没有找到相关介绍)。下面是作者对这个判断的解释,

Alot of times the first paragraph might be the caption under an image so we'll want to make sure if we're going to boost a parent node that it should be connected to other paragraphs, at least for the first n paragraphs so we'll want to make sure that the next sibling is a paragraph and has at least some substantial weight to it.

本节点的得分都会加到父节点,和父节点的父节点。最终从这些父节点中选出得分最高的解释最终的结果。

python-readability

相对于Newspaper python-readability 的代码会更加清晰明了,组织的也较好。 例子中是使用summary()这个方法获得结果,

`readable_article = Document(html).summary()
summary方法还有一个参数``

html_partial```指定返回结果是否需要html 标签。 这个实现会有些区别:

1.移除js, 和css 等不需要的标签 2.把所有div 标签都转成了p标签 3.根据标签的class 属性, 名称对所有p标签打分.(打分规则详见后面的代码)。 4.选择得分最高格式化并返回

打分规则有两部分第一部分是根据class 属性,第二部分是根据tag名称。 下面对不同标签赋予不同权重

`def score_node(self, elem):content_score = self.class_weight(elem)name = elem.tag.lower()if name == "div":content_score += 5elif name in ["pre", "td", "blockquote"]:content_score += 3elif name in ["address", "ol", "ul", "dl", "dd", "dt", "li", "form"]:content_score -= 3elif name in ["h1", "h2", "h3", "h4", "h5", "h6", "th"]:content_score -= 5return {'content_score': content_score,'elem': elem}
class_weight 方法是根据class 的值来打分,打分规则如下``
def class_weight(self, e):    weight = 0    for feature in [e.get('class', None), e.get('id', None)]:        if feature:            if REGEXES['negativeRe'].search(feature):                weight -= 25            if REGEXES['positiveRe'].search(feature):                weight += 25            if self.positive_keywords and self.positive_keywords.search(feature):                weight += 25            if self.negative_keywords and self.negative_keywords.search(feature):                weight -= 25    if self.positive_keywords and self.positive_keywords.match('tag-'+e.tag):        weight += 25    if self.negative_keywords and self.negative_keywords.match('tag-'+e.tag):        weight -= 25    return weight
`其中用到预先定义的正则:

`

REGEXES = { 'unlikelyCandidatesRe':re.compile('combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|adbreak|agegate|pagination|pager|popup|tweet|twitter', re.I), 'okMaybeItsACandidateRe': re.compile('and|article|body|column|main|shadow', re.I), 'positiveRe': re.compile('article|body|content|entry|hentry|main|page|pagination|post|text|blog|story', re.I), 'negativeRe': re.compile('combx|comment|com|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget', re.I), 'divToPElementsRe': re.compile('

```

总结

看了两种实现,其实都是基于一些规则,能写出这样的规则,对html 该要有所熟悉才能完成?但是这些规则终归是死的,当然我有见到其他方式实现,使用了简单的机器学习算法,但是可能效果并不会比这里介绍的好多少。

改进方向

看了很多新闻,发现大部分新闻的摘要都是第一段,看新闻只看第一段大概能知道这个新闻在说什么。这里的第一段并不是严格意义上的第一段。而是新闻前面一部分。自动摘要的结果并不会比第一段的好。所以为了满足自己需求,在python-readability 的结果返回后使用一些类似的规则取第一段作为摘要,还有对中文环境下的新闻可以做些适当调整,这都是在使用过程中能改进的地方

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

1044

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

334

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

213

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

35

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

111

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

77

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

17

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

813

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

97

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号