簡體   English   中英

是否可以找到具有相同dom結構的節點

[英]Is it possible to find the nodes with same dom structure

我從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>

我想提取數據ContentContent2

雖然另一個站點可能使用這樣的結構:

<article class="entry">
    <section class='title'>
        Content3
    </section>
</article>
<article class="entry">
    <section class='title'>
        Conent4
    </section>
</article>

我想提取數據Content3Content4

最簡單的解決方案是為所有站點一一標記所需的數據xpath。 那將是一件乏味的工作。

所以我想知道結構是否可以自動提取。 實際上,我只需要位於重復的根節點(在上面的示例中為div.postarticle.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)

它是這樣的:

  1. 瀏覽HTML文檔,並構造文檔中所有元素路徑及其出現的字典。
  2. 根據您從網頁推斷出的一般規則過濾這些路徑。
  3. 使用一些常見的提取邏輯從這些過濾的路徑中提取內容。

為了構建路徑字典,我只是使用BeautifulSoup文檔,並計算每個元素路徑的出現次數。 以后可以在過濾任務中使用它,以僅保留最多重復的路徑。

接下來,我根據一些基本規則過濾出路徑。 為了保留路徑,它必須:

  • 發生至少min_occurs ,最多max_occurs倍。
  • 長度至少為min_depth ,最大為max_depth
  • 匹配pattern

可以以類似方式添加其他規則。

最后一部分遍歷過濾后留下的路徑,並使用一些使用extract_content定義的通用邏輯從元素中提取內容。

如果您的網頁非常簡單,並且可以推斷出此類規則,則可能會起作用。 否則,您將不得不考慮某種我認為是機器學習的任務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM