网页内容抓取进阶:解析JavaScript动态加载的数据

DDD
发布: 2025-10-05 12:02:31
原创
222人浏览过

网页内容抓取进阶:解析JavaScript动态加载的数据

本教程旨在解决使用BeautifulSoup直接解析HTML元素时,无法获取到通过JavaScript动态加载内容的常见问题。我们将深入探讨当目标文本被嵌入到<script>标签内的JavaScript变量(如window.__INITIAL_STATE__)中时,如何结合使用requests库、<a style="color:#f60; text-decoration:underline;" title= "正则表达式"href="https://www.php.cn/zt/15947.html" target="_blank">正则表达式和<a style="color:#f60; text-decoration:underline;" title= "js"href="https://www.php.cn/zt/15802.html" target="_blank">json模块来准确提取所需数据,并最终利用BeautifulSoup对提取出的HTML片段进行清洗,从而实现更高效、更精准的网页内容抓取。<h3>传统HTML解析的局限性<p>在进行网页数据抓取时,我们经常会遇到内容无法通过简单的<a style="color:#f60; text-decoration:underline;" title= "html"href="https://www.php.cn/zt/15763.html" target="_blank">html标签选择器获取的情况。例如,当尝试使用beautifulsoup的find_all('p')方法来提取段落文本时,可能会发现返回的文本为空,或者只获取到不相关的部分,甚至出现nameerror: name 'text' is not defined这样的错误。这通常是因为目标内容并非直接存在于页面的静态html结构中,而是通过<a style="color:#f60; text-decoration:underline;" title= "javascript"href="https://www.php.cn/zt/15724.html" target="_blank">javascript在页面加载后动态注入的。<p>以提供的案例为例,尽管页面HTML中存在<p>标签,但我们真正想要的文章标题和摘要文本并未直接包含在这些可见的<p>标签内。相反,它们被封装在一个名为window.__INITIAL_STATE__的JavaScript变量中,以JSON格式存储在页面的<script>标签内部。<p>原始尝试代码示例:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">import requests from bs4 import BeautifulSoup URL = &quot;https://habr.com/ru/hubs/gamedev/articles/&quot; page = requests.get(URL).content soup = BeautifulSoup(page, &quot;html.parser&quot;) post = soup.find(&quot;article&quot;, class_=&quot;tm-articles-list__item&quot;) # 这里的discription可能为空或不包含所需内容 discription = post.find_all('p') for post_text in discription: text = post_text.get_text() # 如果discription为空,text变量将不会被定义,导致NameError print(text)</pre>
登录后复制
</div><p>这种方法在面对动态加载内容时会失效,因为BeautifulSoup只能解析requests.get()获取到的原始HTML文本,而不能执行JavaScript来渲染页面。<h3>识别动态加载内容<p>要判断目标内容是否为动态加载,可以通过以下步骤:<p><span>立即学习“<a href="https://pan.quark.cn/s/c1c2c2ed740f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Java免费学习笔记(深入)”;<ol><li><strong>查看页面源代码: 在<a style="color:#f60; text-decoration:underline;" title= "浏览器"href="https://www.php.cn/zt/16180.html" target="_blank">浏览器中右键点击页面,选择“查看页面源代码”(或“View Page Source”)。搜索你想要抓取的内容,如果找不到,或者只找到一些占位符,那么很可能就是动态加载的。<li><strong>检查开发者工具的网络请求: 打开浏览器的开发者工具(F12),切换到“网络”(Network)选项卡。刷新页面,观察是否有XHR(XMLHttpRequest)或Fetch请求加载了包含目标数据的新数据。<li><strong>检查<script>标签: 在页面源代码中搜索<script>标签,尤其是那些看起来包含大量JSON数据或定义了全局JavaScript变量的脚本块。例如,window.__INITIAL_STATE__就是一个常见的模式,许多现代<a style="color:#f60; text-decoration:underline;" title= "前端"href="https://www.php.cn/zt/15813.html" target="_blank">前端框架(如React、Vue等)会用它来初始化页面状态。<p>在我们的案例中,通过检查页面源代码,可以发现文章的标题和摘要信息被封装在window.__INITIAL_STATE__这个JavaScript对象中。<h3>解决方案:正则表达式与JSON解析<p>当内容被嵌入到JavaScript变量中时,我们需要采用一种混合策略:<ol><li>使用requests获取页面的原始HTML文本。<li>使用正则表达式从HTML文本中提取包含目标数据的JavaScript变量内容。<li>将提取出的JavaScript变量内容解析为JSON对象。<li>在JSON对象中导航,找到并提取所需的数据。<li>如果提取出的数据仍包含HTML标签,可再次使用BeautifulSoup进行清洗。<h4>步骤一:获取页面原始文本<p>首先,我们需要获取完整的页面文本,而不仅仅是BeautifulSoup解析后的DOM结构。requests.get(URL).text可以获取到包含JavaScript代码的原始字符串。<h4>步骤二:使用正则表达式提取JavaScript变量<p>为了从原始文本中精确地提取window.__INITIAL_STATE__变量的值,我们可以使用正则表达式。观察目标变量的结构,它通常以window.__INITIAL_STATE__=开头,并以特定的字符序列(如}}后跟分号)结束。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">import re # ... (其他导入) page = requests.get(URL).text # 使用正则表达式匹配并提取window.__INITIAL_STATE__变量的内容 # 注意:(.*)}}; 捕获了从等号后到第一个}};之间的所有内容 data_match = re.search(r&quot;window\.__INITIAL_STATE__=(.*}});&quot;, page) if data_match: data_str = data_match.group(1) else: print(&quot;未找到 window.__INITIAL_STATE__ 数据。&quot;) exit()</pre>
登录后复制
</div><p>这里的正则表达式r"window\.__INITIAL_STATE__=(.*}});"的含义是:<ul><li>window\.__INITIAL_STATE__=:匹配字面字符串window.__INITIAL_STATE__=。_是特殊字符,需要转义。<li>(.*):这是一个捕获组,.*匹配任意字符(除了换行符)零次或多次。它将捕获=之后的所有内容。<li>}});:匹配字面字符串}});,作为变量内容的结束标志。<h4>步骤三:解析JSON数据<p>提取到的data_str是一个JSON格式的字符串,我们需要使用<a style="color:#f60; text-decoration:underline;" title= "json"href="https://www.php.cn/zt/15848.html" target="_blank">json模块将其转换为Python字典或列表。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">import json # ... (其他代码) data = json.loads(data_str)</pre>
登录后复制
</div><h4>步骤四:导航至目标数据<p>一旦数据被解析为Python对象,我们就可以像操作普通字典和列表一样,通过键和索引来访问所需的信息。这通常需要对目标网站的JSON结构有所了解,可以通过浏览器开发者工具(Network -> XHR/Fetch -> Response 或 Console -> window.__INITIAL_STATE__)进行探索。<p>在提供的案例中,文章数据位于data["articlesList"]["articlesList"]中。我们可以遍历这个字典,并根据时间戳进行排序,以获取最新的文章。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"># ... (其他代码) for article_id, article_data in sorted( data[&quot;articlesList&quot;][&quot;articlesList&quot;].items(), key=lambda item: item[1][&quot;timePublished&quot;], # 根据发布时间排序 reverse=True, # 倒序,获取最新文章 ): # 提取文章标题 title = article_data[&quot;titleHtml&quot;] # 提取文章摘要,可能包含HTML标签 lead_text_html = article_data[&quot;leadData&quot;][&quot;textHtml&quot;] # 我们只取第一篇文章作为示例 break</pre>
登录后复制
</div><h4>步骤五:处理HTML片段<p>从JSON中提取出的lead_text_html可能仍然包含HTML标签(如<strong>、<a>等)。为了获取纯文本,我们可以再次利用BeautifulSoup。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"># ... (其他代码) # 使用BeautifulSoup清洗摘要中的HTML标签 clean_lead_text = BeautifulSoup(lead_text_html, &quot;html.parser&quot;).text print(title) print(clean_lead_text)</pre>
登录后复制
</div><h3>完整示例代码<p>结合上述步骤,完整的解决方案代码如下:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">import re import json import requests from bs4 import BeautifulSoup URL = &quot;https://habr.com/ru/hubs/gamedev/articles/&quot; # 目标网站URL # 1. 获取页面原始文本 page = requests.get(URL).text # 2. 使用正则表达式从页面文本中提取JavaScript变量__INITIAL_STATE__的内容 # 匹配从&quot;window.__INITIAL_STATE__=&quot;开始,到第一个&quot;}};&quot;结束的JSON字符串 data_match = re.search(r&quot;window\.__INITIAL_STATE__=(.*}});&quot;, page) if data_match: data_str = data_match.group(1) else: print(&quot;错误:未能在页面中找到 'window.__INITIAL_STATE__' 数据。&quot;) exit() # 3. 解析提取到的JSON字符串 data = json.loads(data_str) # 4. 导航至目标数据并提取信息 # 遍历文章列表,并按发布时间倒序排序,以获取最新文章 for article_id, article_data in sorted( data[&quot;articlesList&quot;][&quot;articlesList&quot;].items(), key=lambda item: item[1][&quot;timePublished&quot;], reverse=True, ): # 提取文章标题(通常是HTML片段) title_html = article_data[&quot;titleHtml&quot;] # 提取文章摘要(通常是HTML片段) lead_data_html = article_data[&quot;leadData&quot;][&quot;textHtml&quot;] # 5. 使用BeautifulSoup清洗HTML片段,获取纯文本 clean_title = BeautifulSoup(title_html, &quot;html.parser&quot;).text clean_lead_text = BeautifulSoup(lead_data_html, &quot;html.parser&quot;).text print(f&quot;标题: {clean_title}&quot;) print(f&quot;摘要: {clean_lead_text}\n&quot;) # 示例中我们只获取第一篇文章,然后退出循环 break</pre>
登录后复制
</div><p>输出结果示例:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">标题: 30 лет DOOM: новый код — новые баги 摘要: Сегодня первой игре из серии DOOM исполняется ровно 30 лет! Мы не могли обойти стороной это событие и в честь этого решили посмотреть, как же выглядит код этой легендарной игры спустя годы.</pre>
登录后复制
</div><h3>注意事项<ul><li><strong>页面结构变化: 网站的HTML结构或JavaScript变量名/JSON结构可能会随时间变化。如果网站更新,您的正则表达式或JSON路径可能需要调整。<li><strong>正则表达式的鲁棒性: 正则表达式需要足够精确以避免误匹配,但也要足够灵活以应对微小的格式差异。过于严格的正则可能因细微变化而失效。<li><strong>JSON结构探索: 在编写代码之前,花时间在浏览器开发者工具中仔细检查目标JSON数据的结构是至关重要的。<li><strong>错误处理: 在实际项目中,应加入更完善的错误处理机制,例如使用try-except块来处理requests请求失败、正则表达式匹配失败或JSON解析错误等情况。<li><strong>性能考量: 对于大规模抓取,频繁地使用正则表达式和JSON解析可能会有性能开销。考虑缓存或优化数据处理逻辑。<h3>总结<p>当传统的HTML解析工具BeautifulSoup无法直接获取网页内容时,这通常意味着内容是通过JavaScript动态加载的。通过结合requests获取原始页面文本,使用re模块的正则表达式提取嵌入在<script>标签中的JavaScript变量(尤其是JSON格式的数据),再通过json模块进行解析,我们能够有效地获取这些动态内容。最后,BeautifulSoup仍然可以用于清洗从JSON中提取出的HTML片段,确保获得纯净的文本数据。这种多工具组合的方法是处理现代复杂网页抓取任务的关键技能。</script>

以上就是网页内容抓取进阶:解析JavaScript动态加载的数据的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号