目录
The Detail of Extracting & Curating Articles
相关 简介
对比
Newspaper 源码简析
代码结构
download
正文提取
python-readability
总结
改进方向
首页 web前端 html教程 The Detail of Extracting & Curating Articles_html/css_WEB-ITnose

The Detail of Extracting & Curating Articles_html/css_WEB-ITnose

Jun 24, 2016 am 11:15 AM

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()
登录后复制

```

正文提取

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

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工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1662
14
CakePHP 教程
1419
52
Laravel 教程
1313
25
PHP教程
1262
29
C# 教程
1236
24
了解HTML,CSS和JavaScript:初学者指南 了解HTML,CSS和JavaScript:初学者指南 Apr 12, 2025 am 12:02 AM

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

HTML,CSS和JavaScript的角色:核心职责 HTML,CSS和JavaScript的角色:核心职责 Apr 08, 2025 pm 07:05 PM

HTML定义网页结构,CSS负责样式和布局,JavaScript赋予动态交互。三者在网页开发中各司其职,共同构建丰富多彩的网站。

HTML,CSS和JavaScript:Web开发人员的基本工具 HTML,CSS和JavaScript:Web开发人员的基本工具 Apr 09, 2025 am 12:12 AM

HTML、CSS和JavaScript是Web开发的三大支柱。1.HTML定义网页结构,使用标签如、等。2.CSS控制网页样式,使用选择器和属性如color、font-size等。3.JavaScript实现动态效果和交互,通过事件监听和DOM操作。

HTML:结构,CSS:样式,JavaScript:行为 HTML:结构,CSS:样式,JavaScript:行为 Apr 18, 2025 am 12:09 AM

HTML、CSS和JavaScript在Web开发中的作用分别是:1.HTML定义网页结构,2.CSS控制网页样式,3.JavaScript添加动态行为。它们共同构建了现代网站的框架、美观和交互性。

HTML的未来:网络设计的发展和趋势 HTML的未来:网络设计的发展和趋势 Apr 17, 2025 am 12:12 AM

HTML的未来充满了无限可能。1)新功能和标准将包括更多的语义化标签和WebComponents的普及。2)网页设计趋势将继续向响应式和无障碍设计发展。3)性能优化将通过响应式图片加载和延迟加载技术提升用户体验。

HTML,CSS和JavaScript的未来:网络开发趋势 HTML,CSS和JavaScript的未来:网络开发趋势 Apr 19, 2025 am 12:02 AM

HTML的未来趋势是语义化和Web组件,CSS的未来趋势是CSS-in-JS和CSSHoudini,JavaScript的未来趋势是WebAssembly和Serverless。1.HTML的语义化提高可访问性和SEO效果,Web组件提升开发效率但需注意浏览器兼容性。2.CSS-in-JS增强样式管理灵活性但可能增大文件体积,CSSHoudini允许直接操作CSS渲染。3.WebAssembly优化浏览器应用性能但学习曲线陡,Serverless简化开发但需优化冷启动问题。

HTML与CSS vs. JavaScript:比较概述 HTML与CSS vs. JavaScript:比较概述 Apr 16, 2025 am 12:04 AM

HTML、CSS和JavaScript在网页开发中的角色分别是:HTML负责内容结构,CSS负责样式,JavaScript负责动态行为。1.HTML通过标签定义网页结构和内容,确保语义化。2.CSS通过选择器和属性控制网页样式,使其美观易读。3.JavaScript通过脚本控制网页行为,实现动态和交互功能。

HTML:建立网页的结构 HTML:建立网页的结构 Apr 14, 2025 am 12:14 AM

HTML是构建网页结构的基石。1.HTML定义内容结构和语义,使用、、等标签。2.提供语义化标记,如、、等,提升SEO效果。3.通过标签实现用户交互,需注意表单验证。4.使用、等高级元素结合JavaScript实现动态效果。5.常见错误包括标签未闭合和属性值未加引号,需使用验证工具。6.优化策略包括减少HTTP请求、压缩HTML、使用语义化标签等。

See all articles