新闻中心
Python爬取动态加载内容的隐藏电话号码:API请求方法详解

本教程旨在解决使用beautifulsoup无法直接爬取动态加载内容中隐藏电话号码的问题。当目标网站通过j*ascript异步请求(如graphql api)动态更新dom时,传统的html解析器将失效。文章详细介绍了如何利用浏览器开发者工具分析网络请求,识别数据源api,并使用python的`requests`库模拟这些api请求,从而高效准确地获取所需数据。
在现代网页中,许多内容并非直接嵌入在初始HTML文档中,而是通过J*aScript在用户交互(例如点击按钮)后异步加载。对于这类动态内容,仅依赖于BeautifulSoup这样的静态HTML解析库是不足以获取到完整信息的。本文将以从弹出按钮中抓取隐藏电话号码为例,详细讲解如何通过模拟API请求来解决这一挑战。
1. 理解动态内容加载的挑战
当你尝试使用requests库获取网页内容并用BeautifulSoup解析时,如果目标数据(如电话号码)只有在点击某个按钮后才显示,那么你获取到的HTML将不包含这些数据。这是因为BeautifulSoup只能处理服务器返回的原始HTML。而按钮点击后触发的数据加载通常是通过浏览器执行J*aScript代码,向后端API发送请求,然后将返回的数据动态插入到网页DOM中。
在我们的例子中,点击“التواصل”按钮后弹出的电话号码,就是通过J*aScript向一个GraphQL API发送POST请求获取的。
2. 利用浏览器开发者工具分析网络请求
要获取动态加载的数据,我们首先需要找出是哪个API提供了这些数据。浏览器开发者工具(通常按F12键打开)的“网络”(Network)选项卡是关键。
- 打开目标网页: 访问你想要爬取的页面,例如 https://haraj.com.sa/1194697687。
- 打开开发者工具: 在浏览器中按F12,切换到“网络”(Network)选项卡。
- 筛选XHR/Fetch请求: 在网络面板中,通常会有筛选器,选择“XHR”或“Fetch/XHR”,这样可以只显示J*aScript发起的异步请求。
- 触发数据加载: 点击网页上的“التواصل”按钮。
-
识别API请求: 在网络面板中观察新出现的请求。通常,你会看到一个POST请求,其URL可能包含“graphql”或“api”等字样。点击该请求,查看其详细信息:
- URL: 请求的目标地址(例如 https://graphql.haraj.com.sa)。
- 请求方法: 通常是POST。
- 请求头(Request Headers): 包含User-Agent等信息。
- 请求载荷(Request Payload): 这是最重要的部分,它包含了发送给API的数据,通常是JSON格式。对于GraphQL,你会看到query和variables等字段。
- 响应(Response): API返回的数据,通常也是JSON格式,其中包含我们所需的电话号码。
通过分析,我们可以发现当点击按钮时,浏览器向 https://graphql.haraj.com.sa 发送了一个POST请求,请求载荷中包含一个GraphQL查询,以及一个postId变量。
3. 提取关键参数:postId
在分析请求载荷时,我们注意到一个名为postId的变量是动态的。这个postId通常可以从原始网页的URL中提取。例如,如果页面URL是 https://haraj.com.sa/1194697687,那么postId可能就是URL末尾的数字部分,但可能需要去除某些前缀。
Tanka
具备AI长期记忆的下一代团队协作沟通工具
146
查看详情
根据观察,URL中的1194697687对应的postId是94697687,这意味着需要去除前两位数字11。
以下是一个提取postId的示例函数:
import re
def extract_post_id_from_url(url):
"""
从Haraj网站的URL中提取postId。
示例: "https://haraj.com.sa/1194697687" -> 94697687
"""
match = re.search(r'/(\d+)$', url)
if match:
full_id_str = match.group(1)
# 根据观察,postId是URL末尾数字去除前两位"11"后的部分
if full_id_str.startswith('11') and len(full_id_str) > 2:
return int(full_id_str[2:])
return int(full_id_str) # 如果没有"11"前缀,则直接返回
return None
# 示例用法
target_url = "https://haraj.com.sa/1194697687"
post_id = extract_post_id_from_url(target_url)
if post_id:
print(f"提取到的 Post ID: {post_id}")
else:
print("无法从URL中提取 Post ID。")4. 模拟API请求获取数据
一旦我们识别了API请求的URL、方法、头部和载荷,就可以使用Python的requests库来模拟这个请求。
import requests
import re
def extract_post_id_from_url(url):
"""
从Haraj网站的URL中提取postId。
示例: "https://haraj.com.sa/1194697687" -> 94697687
"""
match = re.search(r'/(\d+)$', url)
if match:
full_id_str = match.group(1)
# 根据观察,postId是URL末尾数字去除前两位"11"后的部分
if full_id_str.startswith('11') and len(full_id_str) > 2:
return int(full_id_str[2:])
return int(full_id_str) # 如果没有"11"前缀,则直接返回
return None
def get_hidden_phone_number(page_url):
"""
通过模拟API请求获取隐藏的电话号码。
"""
# 1. 从页面URL中提取 postId
post_id = extract_post_id_from_url(page_url)
if post_id is None:
print(f"错误: 无法从URL '{page_url}' 中提取有效的 postId。")
return None
# 2. 定义API请求参数
api_url = "https://graphql.haraj.com.sa"
# 根据浏览器网络分析,这些参数可能为空或特定值
params = {
"queryName": "postContact",
"token": "",
"clientId": "",
"version": ""
}
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
"accept": "*/*",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/json",
"origin": "https://haraj.com.sa",
"referer": page_url # 设置referer以模拟真实浏览器行为
}
# GraphQL请求的Payload
payload = {
"query": "query postContact($postId: Int!) {postContact(postId: $postId){contactText}}",
"variables": {
"postId": post_id # 使用动态获取的postId
}
}
try:
# 3. 发送POST请求
response = requests.post(api_url, params=params, headers=headers, json=payload)
response.raise_for_status() # 检查HTTP请求是否成功
# 4. 解析JSON响应
data = response.json()
# 提取电话号码
contact_text = data.get('data', {}).get('postContact', {}).get('contactText')
return contact_text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
except KeyError as e:
print(f"解析响应数据失败: 缺少键 {e}")
return None
# 主函数调用示例
if __name__ == "__main__":
target_page_url = "https://haraj.com.sa/1194697687" # 替换为实际的页面URL
phone_number = get_hidden_phone_number(target_page_url)
if phone_number:
print(f"成功获取到电话号码: {phone_number}")
else:
print("未能获取电话号码。")
# 另一个示例URL
another_page_url = "https://haraj.com.sa/1199808969"
phone_number_2 = get_hidden_phone_number(another_page_url)
if phone_number_2:
print(f"成功获取到另一个电话号码: {phone_number_2}")
else:
print("未能获取另一个电话号码。")代码解释:
- extract_post_id_from_url(url): 这个函数负责从给定的Haraj网站URL中解析出postId。它使用正则表达式匹配URL末尾的数字,并根据观察到的模式(去除前缀11)进行处理。
-
get_hidden_phone_number(page_url):
- 首先调用extract_post_id_from_url获取当前页面的postId。
- api_url:这是通过开发者工具识别出的GraphQL API的端点。
- params:查询字符串参数,即使为空也应包含,以模拟浏览器行为。
- headers:模拟浏览器请求头,特别是User-Agent、Content-Type、Origin和Referer,这有助于避免被网站识别为爬虫。
- payload:这是一个字典,会被requests.post自动转换为JSON格式发送。它包含了GraphQL查询语句和动态的postId变量。
- requests.post(...):发送POST请求。json=payload参数会自动设置Content-Type为application/json并序列化payload。
- response.raise_for_status():这是一个好习惯,如果HTTP请求返回的状态码表示错误(例如4xx或5xx),它会抛出一个HTTPError。
- response.json():将API返回的JSON响应解析为Python字典。
- 通过字典的get方法安全地访问嵌套数据,提取contactText,即电话号码。
- 增加了错误处理机制,捕获requests请求异常和JSON解析异常。
5. 注意事项与总结
- 动态参数: 许多API请求中可能包含动态生成的令牌(token)、客户端ID(clientId)或会话ID。如果这些参数是必需的,你可能需要先爬取主页面,通过J*aScript代码或隐藏字段来提取它们。本例中的token、clientId和version在当前场景下似乎不是必需的,但实际情况可能不同。
- User-Agent: 始终设置一个合理的User-Agent头部,以模拟真实浏览器,降低被网站封禁的风险。
- 错误处理: 编写健壮的代码,处理网络请求失败、JSON解析失败或预期数据结构缺失等情况。
- 频率限制与道德: 遵守网站的robots.txt协议,不要发送过高的请求频率,避免对目标网站造成不必要的负担。
- GraphQL的优势: GraphQL允许客户端精确地指定所需的数据,这在某些情况下比REST API更高效,但也意味着你需要理解其查询语法。
通过上述方法,我们成功绕过了BeautifulSoup在处理动态加载内容时的局限性,直接与网站的后端API交互,高效准确地获取了隐藏的电话号码。这种模拟API请求的技术是爬取现代动态网站的关键技能之一。
以上就是Python爬取动态加载内容的隐藏电话号码:API请求方法详解的详细内容,更多请关注其它相关文章!
# python
# html建设网站
# 潍坊seo网站优化
# 推广网站有什么好的方法
# 泸西网站搜索优化平台
# 出海网站建设
# seo资源vip
# 网站建设教学点
# 扬州关键词排名工作室
# 柳州营销推广效果好
# 如果没有
# 这是一个
# 你会
# 鼠标
# 这是
# 数据结构
# 所需
# 两位
# 加载
# 工具
# app
# 浏览器
# windows
# 正则表达式
# json
# js
# html
# java
# javascript
# 微信营销推广注意事项
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
vivo浏览器自带的下载器速度慢怎么办 vivo浏览器提升文件下载速度的技巧
QQ邮箱网页版入口 QQ邮箱官方邮箱登录通道
海棠账号登录入口_登录海棠账户同步阅读记录
小红书商家版怎样在笔记嵌入商品卡路径_小红书商家版在笔记嵌入商品卡路径【挂载教程】
漫画星球免费下拉式入口 漫画星球免费漫画在线阅读网站
Python多版本共存与虚拟环境管理深度指南
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享
夸克浏览器桌面版同步不了书签怎么处理 夸克浏览器跨设备同步异常解决方案
excel怎么制作工资条 excel快速生成工资条的方法
Typer应用中灵活处理命令行参数的令牌化与解析
C++如何使用AddressSanitizer(ASan)_C++调试工具中检测内存访问错误的利器
PostgreSQL海量数据高效导入策略:Python与Django实践指南
夸克AO3官网入口_AO3镜像网站2025推荐
C++如何进行游戏物理模拟_使用Box2D库为C++游戏添加2D物理效果
在Go Martini框架中高效服务动态生成图像的实践指南
如何使用Node.js csv 包按条件移除含空字段的CSV记录
c++20的std::jthread是什么_c++可中断线程与RAII式管理
如何将HTML表格多行数据保存到Google Sheet
Safari怎么安装扩展程序 浏览器插件安装与管理方法【详解】
抖音网页版平台入口 抖音网页版官网在线访问教程
在J*a中如何在J*a中使用异常机制记录错误日志_异常日志实践经验
漫蛙官网正版漫画入口 漫蛙2官方网页登录地址
163邮箱官方主页登录 直达网易邮箱登录核心页面
J*a TimerTask文件监控:HashMap状态管理与常见陷阱规避指南
Web Components中自定义开关组件状态同步的常见陷阱与解决方案
解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException
2025年云电脑操作系统体验 | 无需本地硬件,随时随地使用高性能PC
豆包手机助手发布技术预览版:直接嵌入手机系统!努比亚样机发售
在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析
Win11蓝牙耳机断连怎么解决 Win11蓝牙设置重新配对与驱动更新【技巧】
极速漫画官方主页网址 极速漫画漫画在线浏览官网链接
Mudbox图层蒙版怎么用_Mudbox图层蒙版数字雕刻应用技巧
b站赚钱渠道_b站收益来源
C++如何实现线程池_C++11手动实现一个简单的固定大小线程池
C++如何实现异步操作_C++11使用std::future和std::async进行异步编程
sublime如何配置Go语言开发环境_sublime搭建Golang编译运行系统
Win10如何恢复误删的快捷方式_Win10重建常用软件快捷方式
AO3官方镜像站点汇总 AO3同人作品网页版直达链接
Promise错误处理:在catch后终止链式then执行的策略
msn官网入口地址手机版 msn官方网站手机最新链接
c++如何实现单例设计模式_c++线程安全的单例模式写法
在J*a中如何使用Exception包装底层异常_异常包装与信息传递方法说明
神经网络二分类模型训练异常:高损失与完美验证准确率的排查与修正
《GTA6》开发画面疑似泄露!这次可不是AI了
Windows10怎么开启夜间模式 Windows10系统设置调整色温与亮度缓解夜间用眼疲劳【教程】
Win10怎么制作U盘启动盘 Win10系统安装U盘制作教程【详解】
uc浏览器网页版入口 uc浏览器网页版最新网址
抖音商城签到领现金是真的吗_抖音商城签到奖励与提现说明
微博网页版官方账号登录 微博网页版内容浏览使用指南
Yandex浏览器官方网页版入口 Yandex浏览器最新版官网


2025-11-13
浏览次数:次
返回列表