【问题标题】:HTML structure into network graph将 HTML 结构转换为网络图
【发布时间】:2019-05-17 22:34:45
【问题描述】:

我要做的是将 HTML 站点 DOM(文档对象模型)表示为网络图,然后使用该图进行一些统计计算(如度数、介数、接近度、绘图等)。 )。我找不到任何直接执行此操作的库或以前的 SO 帖子。我的想法是使用BeautifulSoup Library,然后是Networkx Library。我尝试编写一些代码循环遍历 HTML 结构的每个元素(使用 recursive=True)。但我不知道如何识别每个唯一标签(您在这里看到,在图中添加第二个 h1 节点会覆盖第一个节点,对于父母来说也是如此,因此该图最终完全是错误的)。

import networkx as nx
import bs4
from bs4 import BeautifulSoup
ex0 = "<html><head><title>Are you lost ?</title></head><body><h1>Lost on the Intenet ?</h1><h1>Don't panic, we will help you</h1><strong><pre>    * <----- you are here</pre></strong></body></html>"
soup = BeautifulSoup(ex0)
G=nx.Graph()
for tag in soup.findAll(recursive=True):
    G.add_node(tag.name)
    G.add_edge(tag.name, tag.findParent().name)
nx.draw(G)   
G.nodes
#### NodeView(('html', '[document]', 'head', 'title', 'body', 'h1', 'strong', 'pre'))

关于如何完成的任何想法(包括完全不同的方法)。谢谢

PS:图可以有向与否,我不在乎。

【问题讨论】:

  • 您必须循环所有嵌套元素。 stackoverflow.com/questions/36108621/…
  • @PedroLobito 谢谢,我已经这样做了,但我的问题是标签的唯一性甚至标签值
  • 您可以使用字典来存储每个带有唯一键的标签,即:{'div1', element1, 'div2': element2}
  • 是的,这可能很好,但我不知道如何在我的代码中实现它:-)。 Beautifulsoup 将只接受标准标签,而不接受名称中带有一些识别数字的标签...
  • 我了解,但我也没有时间为您开发自定义答案。 GL!

标签: python dom graph beautifulsoup networkx


【解决方案1】:

您可以遍历每个BeautifulSoup 对象的content 属性。要显示标签,只需使用nx.draw 中的with_labels 属性:

import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict
from bs4 import BeautifulSoup as soup
ex0 = "<html><head><title>Are you lost ?</title></head><body><h1>Lost on the Intenet ?</h1><h1>Don't panic, we will help you</h1><strong><pre>    * <----- you are here</pre></strong></body></html>"
d = soup(ex0, 'html.parser')
def _traverse_html(_d:soup, _graph:nx.Graph, _counter, _parent=None) -> None:
  for i in _d.contents:
     if i.name is not None:
       try:
         _name_count = _counter.get(i.name)
         if _parent is not None:
           _graph.add_node(_parent)
           _graph.add_edge(_parent, i.name if not _name_count else f'{i.name}_{_name_count}')
         _counter[i.name] += 1
         _traverse_html(i, _graph, _counter, i.name)
       except AttributeError:
         pass

_full_graph = nx.Graph()
_traverse_html(d, _full_graph, defaultdict(int))
nx.draw(_full_graph, with_labels = True)   
plt.show()

【讨论】:

  • 您好,感谢您的广泛回答。尽管如此,输出图不应该有循环,因为我希望每个元素都是唯一的,这是我的主要问题。例如,在您的第一个图中,应该有第二个节点 h1 连接到 body。我们怎样才能做到这一点?
  • @agenis 感谢您的评论。我也刚刚注意到networkx 似乎没有显示重复的节点。因此,我为每个 name 元素使用了一个计数器,并在具有相同名称的连续节点上提供了一个“下划线”。
  • 谢谢,这正是我所需要的。我仍然需要理解你的语法,这对我来说有点“高级”:-)
  • @agenis 每个bs4 对象都有一个属性contents,它存储了对象(父)的所有子标签。递归函数遍历传递给它的对象的每个子对象,创建节点和边,然后在每个子对象上再次调用自身。但是,如果bs4.contents 中的元素不是另一个bs4 对象,则会引发AttributeError(它是标签之间的文本)。 try/except 块捕获后一个错误。
  • 谢谢,确实很聪明。最后一件事,-&gt; none: 是怎么回事我不知道这种语法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 2021-02-09
相关资源
最近更新 更多