我通过Scrapy从很多网站爬取了很多html(内容相似),但dom结构不同。
例如,其中一个网站使用以下结构:
<div class="post">
<section class='content'>
Content1
</section>
<section class="panel">
</section>
</div>
<div class="post">
<section class='content'>
Conent2
</section>
<section class="panel">
</section>
</div>
我想提取数据Content
和Content2
。
虽然另一个网站可能使用这样的结构:
<article class="entry">
<section class='title'>
Content3
</section>
</article>
<article class="entry">
<section class='title'>
Conent4
</section>
</article>
我想提取数据Content3
和Content4
。
而最简单的解决方案是为所有站点一一标记所需的数据xpath。那将是一项乏味的工作。
所以我想知道是否可以自动提取结构。事实上,我只需要定位到重复的根节点(上面示例中的 div.post
和 article.entry
),然后我可以使用一些提取数据一定的规则。
这可能吗?
顺便说一句,我不太清楚这种算法的名称,所以这篇文章的标签可能有误,如果属实请随意修改。
最佳答案
您必须至少了解一些常见模式才能制定确定性提取规则。下面的解决方案非常原始,绝不是最佳的,但它可能会对您有所帮助:
# -*- coding: utf-8 -*-
import re
import bs4
from bs4 import element
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example"
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
min_occurs = 5
max_occurs = 1000
min_depth = 7
max_depth = 7
pattern = re.compile('^/html/body/.*/(span|div)$')
extract_content = lambda e: e.css('::text').extract_first()
#extract_content = lambda e: ' '.join(e.css('*::text').extract())
doc = bs4.BeautifulSoup(response.body, 'html.parser')
paths = {}
self._walk(doc, '', paths)
paths = self._filter(paths, pattern, min_depth, max_depth,
min_occurs, max_occurs)
for path in paths.keys():
for e in response.xpath(path):
yield {'content': extract_content(e)}
def _walk(self, doc, parent, paths):
for tag in doc.children:
if isinstance(tag, element.Tag):
path = parent + '/' + tag.name
paths[path] = paths.get(path, 0) + 1
self._walk(tag, path, paths)
def _filter(self, paths, pattern, min_depth, max_depth, min_occurs, max_occurs):
return dict((path, count) for path, count in paths.items()
if pattern.match(path) and
min_depth <= path.count('/') <= max_depth and
min_occurs <= count <= max_occurs)
它的工作原理如下:
- 探索 HTML 文档并构建文档中所有元素路径及其出现次数的字典。
- 根据您从网页推断出的一般规则过滤这些路径。
- 使用一些常见的提取逻辑从这些过滤路径中提取内容。
为了构建路径字典,我只需使用 BeautifulSoup
遍历文档并计算每个元素路径的出现次数。这可以稍后用于过滤任务,以仅保留最重复的路径。
接下来我根据一些基本规则过滤掉路径。要保留路径,必须:
- 至少出现
min_occurrs
次,最多出现max_occurrs
次。 - 长度至少为
min_depth
,最多为max_depth
。 - 匹配
模式
。
可以以类似的方式添加其他规则。
最后一部分循环遍历过滤后离开的路径,并使用 extract_content
定义的一些通用逻辑从元素中提取内容。
如果您的网页相当简单并且您可以推断出此类规则,那么它可能会起作用。否则,我猜你将不得不看看某种机器学习任务。
关于python - 是否可以找到具有相同dom结构的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45260585/