
在进行网页数据抓取时,我们经常会遇到内容无法通过简单的html标签选择器获取的情况。例如,当尝试使用beautifulsoup的find_all('p')方法来提取段落文本时,可能会发现返回的文本为空,或者只获取到不相关的部分,甚至出现nameerror: name 'text' is not defined这样的错误。这通常是因为目标内容并非直接存在于页面的静态html结构中,而是通过javascript在页面加载后动态注入的。
以提供的案例为例,尽管页面HTML中存在<p>标签,但我们真正想要的文章标题和摘要文本并未直接包含在这些可见的<p>标签内。相反,它们被封装在一个名为window.__INITIAL_STATE__的JavaScript变量中,以JSON格式存储在页面的<script>标签内部。
原始尝试代码示例:
import requests 
from bs4 import BeautifulSoup
URL = "https://habr.com/ru/hubs/gamedev/articles/"
page = requests.get(URL).content
soup = BeautifulSoup(page, "html.parser")
post = soup.find("article", class_="tm-articles-list__item")
# 这里的discription可能为空或不包含所需内容
discription = post.find_all('p')
for post_text in discription:
    text = post_text.get_text()
# 如果discription为空,text变量将不会被定义,导致NameError
print(text)这种方法在面对动态加载内容时会失效,因为BeautifulSoup只能解析requests.get()获取到的原始HTML文本,而不能执行JavaScript来渲染页面。
要判断目标内容是否为动态加载,可以通过以下步骤:
立即学习“Java免费学习笔记(深入)”;
在我们的案例中,通过检查页面源代码,可以发现文章的标题和摘要信息被封装在window.__INITIAL_STATE__这个JavaScript对象中。
当内容被嵌入到JavaScript变量中时,我们需要采用一种混合策略:
首先,我们需要获取完整的页面文本,而不仅仅是BeautifulSoup解析后的DOM结构。requests.get(URL).text可以获取到包含JavaScript代码的原始字符串。
为了从原始文本中精确地提取window.__INITIAL_STATE__变量的值,我们可以使用正则表达式。观察目标变量的结构,它通常以window.__INITIAL_STATE__=开头,并以特定的字符序列(如}}后跟分号)结束。
import re
# ... (其他导入)
page = requests.get(URL).text
# 使用正则表达式匹配并提取window.__INITIAL_STATE__变量的内容
# 注意:(.*)}}; 捕获了从等号后到第一个}};之间的所有内容
data_match = re.search(r"window\.__INITIAL_STATE__=(.*}});", page)
if data_match:
    data_str = data_match.group(1)
else:
    print("未找到 window.__INITIAL_STATE__ 数据。")
    exit()这里的正则表达式r"window\.__INITIAL_STATE__=(.*}});"的含义是:
提取到的data_str是一个JSON格式的字符串,我们需要使用json模块将其转换为Python字典或列表。
import json # ... (其他代码) data = json.loads(data_str)
一旦数据被解析为Python对象,我们就可以像操作普通字典和列表一样,通过键和索引来访问所需的信息。这通常需要对目标网站的JSON结构有所了解,可以通过浏览器开发者工具(Network -> XHR/Fetch -> Response 或 Console -> window.__INITIAL_STATE__)进行探索。
在提供的案例中,文章数据位于data["articlesList"]["articlesList"]中。我们可以遍历这个字典,并根据时间戳进行排序,以获取最新的文章。
# ... (其他代码)
for article_id, article_data in sorted(
    data["articlesList"]["articlesList"].items(),
    key=lambda item: item[1]["timePublished"], # 根据发布时间排序
    reverse=True, # 倒序,获取最新文章
):
    # 提取文章标题
    title = article_data["titleHtml"]
    # 提取文章摘要,可能包含HTML标签
    lead_text_html = article_data["leadData"]["textHtml"]
    # 我们只取第一篇文章作为示例
    break从JSON中提取出的lead_text_html可能仍然包含HTML标签(如<strong>、<a>等)。为了获取纯文本,我们可以再次利用BeautifulSoup。
# ... (其他代码) # 使用BeautifulSoup清洗摘要中的HTML标签 clean_lead_text = BeautifulSoup(lead_text_html, "html.parser").text print(title) print(clean_lead_text)
结合上述步骤,完整的解决方案代码如下:
import re
import json
import requests
from bs4 import BeautifulSoup
URL = "https://habr.com/ru/hubs/gamedev/articles/"  # 目标网站URL
# 1. 获取页面原始文本
page = requests.get(URL).text
# 2. 使用正则表达式从页面文本中提取JavaScript变量__INITIAL_STATE__的内容
# 匹配从"window.__INITIAL_STATE__="开始,到第一个"}};"结束的JSON字符串
data_match = re.search(r"window\.__INITIAL_STATE__=(.*}});", page)
if data_match:
    data_str = data_match.group(1)
else:
    print("错误:未能在页面中找到 'window.__INITIAL_STATE__' 数据。")
    exit()
# 3. 解析提取到的JSON字符串
data = json.loads(data_str)
# 4. 导航至目标数据并提取信息
# 遍历文章列表,并按发布时间倒序排序,以获取最新文章
for article_id, article_data in sorted(
    data["articlesList"]["articlesList"].items(),
    key=lambda item: item[1]["timePublished"],
    reverse=True,
):
    # 提取文章标题(通常是HTML片段)
    title_html = article_data["titleHtml"]
    # 提取文章摘要(通常是HTML片段)
    lead_data_html = article_data["leadData"]["textHtml"]
    # 5. 使用BeautifulSoup清洗HTML片段,获取纯文本
    clean_title = BeautifulSoup(title_html, "html.parser").text
    clean_lead_text = BeautifulSoup(lead_data_html, "html.parser").text
    print(f"标题: {clean_title}")
    print(f"摘要: {clean_lead_text}\n")
    # 示例中我们只获取第一篇文章,然后退出循环
    break输出结果示例:
标题: 30 лет DOOM: новый код — новые баги 摘要: Сегодня первой игре из серии DOOM исполняется ровно 30 лет! Мы не могли обойти стороной это событие и в честь этого решили посмотреть, как же выглядит код этой легендарной игры спустя годы.
当传统的HTML解析工具BeautifulSoup无法直接获取网页内容时,这通常意味着内容是通过JavaScript动态加载的。通过结合requests获取原始页面文本,使用re模块的正则表达式提取嵌入在<script>标签中的JavaScript变量(尤其是JSON格式的数据),再通过json模块进行解析,我们能够有效地获取这些动态内容。最后,BeautifulSoup仍然可以用于清洗从JSON中提取出的HTML片段,确保获得纯净的文本数据。这种多工具组合的方法是处理现代复杂网页抓取任务的关键技能。
以上就是网页内容抓取进阶:解析JavaScript动态加载的数据的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                 
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                            Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号