記事の抽出とキュレーションの詳細_html/css_WEB-ITnose

WBOY
リリース: 2016-06-24 11:15:11
オリジナル
1204 人が閲覧しました

記事の抽出とキュレーションの詳細

[目次]

最近の仕事には、HTML ページからニュース テキストを抽出する問題が含まれています。この問題を解決できるサードパーティのライブラリは数多くありますが、満足できない機能や中国語に適用できない機能が常に存在します。したがって、この記事では、Newspaper、python-goose、python-readability のこれらのパッケージを使用して、次のニュース抽出の詳細を解釈します。ソース コードを読んでいるので、そこには他のプログラミング スキルが記録されているため、混乱を招くかもしれません。ニュース テキストの解析に興味がある場合のみ、無視してかまいません。

関連紹介

  • Newspaper のコードはあまり良くないと思いますが、そのコアのテキスト抽出部分は python-goose に基づいて実装されており、それは同じであると言えます。ニュースのクローリングから解析までのプロセス全体を実装し、写真、ビデオ、タイトル、テキスト、作成者、時間などのフィールドを抽出します。 主にリクエスト、BeautifulSoup、lxml、その他のパッケージを使用します。 3 つのパッケージの中で、GitHub の Star が長く、現在 3324 個あります。リクエストの作者もそれについてツイートしました。たくさんの星を見ることも私の主な読書プロジェクトです。 使用法:
`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 実装に変更しました

。ニュースレターの主な機能はこのパッケージから借用しているため、具体的な内容についてはニュースレターでのみ紹介します。このパッケージは Python3 をサポートしていません。 使用法:

    `from readability.readability import Documentimport urllibhtml = urllib.urlopen(url).read()readable_article = Document(html).summary()readable_title = Document(html).short_title()
    ログイン後にコピー
  • `
比較

Newspaper parse() はデフォルトで写真とビデオを解析するため、一部のビデオと写真が欠落している場合はエラーが報告されます。効率を考慮すると、写真とビデオは必要ありません。デフォルトですべての関数を解析するのではなく、関数を分離した方がよいでしょう。 Python の可読性は比較的優れています。必要な場合にのみ解析されます。そして、Python の可読性は、まさに私が必要としているページをダウンロードするのに役立ちません。もちろん、Newspaper は HTML の受け渡しもサポートしていますが、その実装は非常に醜く感じられます。 自分で実装したくない場合は、Python 可読性を使用することをお勧めします。

新聞ソースコード分析

コード構造

`├── 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分詞が使われます。ドキュメントに記載されている例に従ってください

ダウンロード

この部分はリクエストを使用しており、マルチスレッド関数をカプセル化してスレッドプールを取り出して Python3 で実装し、テストを作成しました。 ```

スレッドインポートスレッドインポートキューインポートトレースバックから

class Worker(Thread): def

init

(self, Tasks, timeout minutes): Thread.init (self, ) print(self.getName()) self .tasks = タスク self.timeout = タイムアウト秒 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, スレッド数, タイムアウト秒数): self.tasks = queue.Queue(スレッド数) _ 範囲 (スレッド数) 内: ワーカー (self.tasks, timeout_秒)

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', ] インポートリクエストのインポート時間

def task(url): returnrequests.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 urls: task(url) print("singlethread used: ", time.time() - start)

if

name

== '

main

': rrree ``` テキスト抽出

タイトルと著者の抽出は、著者部分がサポートするだけであることは言うまでもなく、私にとってあまり役に立ちません英語を読みました。 以下もルールに基づいています。 一般に、すべての解析はルールに基づいています。いくつかの統計手法が使われていますが、基本的には法則であり、当てはまらない場合も必ずあります。 テキストの抽出は主に次のステップに分かれています:

1. いくつかの不要なタグを削除します。 2. テキストの内容を含むルート ノードを計算して取得します。 3. outpuformat を使用して、2 番目のステップで選択したノードのテキストを出力します。

コアはステップ 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('<(a|blockquote|dl|div|img|ol|p|pre|table|ul)', re.I), 'videoRe': re.compile('https?:\/\/(www.)?(youtube|vimeo).com', re.I), }

```

总结

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

改进方向

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

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート