【问题标题】:Scrape select headings and inner text from a webpage using BeautifulSoup?使用 BeautifulSoup 从网页中抓取选定的标题和内部文本?
【发布时间】:2022-11-14 05:33:06
【问题描述】:

来源 - 博客文章 URL

我想将标题标签的内部文本和该标签内的正文复制到一个看起来像这样的表输出中

H2;{H2 tag inner tex}; {p tag(s) inner text}
H3;{H2 tag inner tex}; {p tag(s) inner text}
H2;{H2 tag inner tex}; {p tag(s) inner text}
H3;{H2 tag inner tex}; {p tag(s) inner text}
H4;{H2 tag inner tex}; {p tag(s) inner text}
...

需要H2、H3、H4标签的内容 这些标签中可能有多个段落,所以用新行分隔它们会很棒。

BeautifulSoup 可以做到这一点吗?

我可以取出标签的内部文本,但不知道如何取出 p 标签的内部文本,尤其是当它们不止一个时。或者对其进行格式化,以便我可以保存为 CSV。

from bs4 import BeautifulSoup
import requests
website = requests.get('https://venngage.com/blog/landing-page-examples/')
preString =  {'h1': '', 'h2': '\t', 'h3':'\t\t', 'h4':'\t\t\t'}
soup = BeautifulSoup(website.content, 'html.parser')
tags = soup.find_all(['h1', 'h2', 'h3'])
for soups in tags:
    preStr = preString[soups.name] if soups.name in preString else ''
    print(preStr+soups.string)

在此先感谢您的帮助。

【问题讨论】:

  • 是的,你可以实现这一点(有和没有 bs4),但到目前为止你尝试了什么?该问题需要足够的代码来实现最小的可重现示例:stackoverflow.com/help/minimal-reproducible-example
  • 感谢您的回复 - 用我尝试过的内容更新了我的帖子
  • 看起来你很接近这个:p_tags = soup.find_all(['p']) 会得到这个。
  • 谢谢 - 是的,我正在努力解决的问题是如何将其格式化为如上所述的表格输出形式

标签: python web-scraping beautifulsoup


【解决方案1】:

我不确定我是否完全理解您希望表格的组织方式(每个标题需要哪些段落?嵌套标题是否可以重叠?),但以下建议的解决方案将为每个标题标签设置一行,然后循环遍历它的兄弟姐妹收集所有p 标签,直到它遇到另一个标题标签:

from bs4 import BeautifulSoup
import requests
import pandas

website = requests.get('https://venngage.com/blog/landing-page-examples/')
preString =  {'h1': '', 'h2': '	', 'h3':'		', 'h4':'			'}


htagNames = [k for k in preString.keys()]
htags = soup.find_all(htagNames)
# if you want from within a particular section
# htags = soup.select_one('article.post').find_all(htagNames) 

for h in htags:
    pStrings = []
    for tag in h.find_next_siblings(htagNames+['p']): 
        if tag.name == 'p' and tag.string is not None: 
            pStrings.append(tag.string)
        if tag.name in htagNames: break
    
    headingRows.append({
        'headingType': h.name, # 'headingText': h.string, 
        'headingText': preString[h.name] + h.get_text(' ' , strip=True),  
        'paragraphs': '
'.join(pStrings)
    }) 

# can filter out heading with no paragraphs with
# headingRows = [hr for hr in headingRows if hr['paragraphs']]
        
# save as csv
pandas.DataFrame(headingRows).to_csv('hRows.csv', index=False)

或者,如果您不确定您想要的 p 标签是否会与标题共享一个父标签,那么您可以盲目地收集所有段落,直到下一个标题:

tags = soup.find_all(htagNames+['p']) 

lastTag = tags[-1]
headingRows = []
hInit = {'headingType': None, 'headingText': None, 'paragraphs': []}
curHeading = dict(hInit) # copy

for i, t in enumerate(tags): 
    if t.name == 'p' and t.string is not None: 
        curHeading['paragraphs'].append(t.string) 
    
    if t.name in preString: 
        curHeading['headingType'] = t.name
        #curHeading['preStr'] = preString[t.name]
        curHeading['headingText'] = preString[t.name] + t.get_text(' ' , strip=True) # + t.string
    
    if t == lastTag or tags[i+1].name in preString:
        # if you want possible paras before 1st heading, remove if condition
        if curHeading['headingType'] is not None :
            curHeading['paragraphs'] ='
'.join(curHeading['paragraphs'])
            headingRows.append(curHeading)
        
        curHeading = dict(hInit) # copy
        curHeading['paragraphs'] = [] 

虽然,这冒着从下面的无标题部分获取段落的风险......


结果看起来像

[excel 自动隐藏前导空格,但 dw 标题文本列的缩进仍然存在]

【讨论】:

  • 非常感谢这一点。这适用于某些人,但对于很多博客文章页面,它会失败并出现以下错误“headingText”:preString[h.name] + h.string, TypeError: can only concatenate str (not "NoneType") to str - - 示例 URLs shopify.com/blog/product-page business.tutsplus.com/articles/… 您的帮助将不胜感激
  • @Outbound 尝试使用h.get_text(' ' , strip=True) 而不是h.string [我没有考虑h_ 标签与其他标签嵌套在里面]
猜你喜欢
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-28
相关资源
最近更新 更多