如何通过Flutter进行网页抓取(Web Scraping)并展示IP详情至应用UI?
从ipcost.com抓取IP数据并在Flutter应用中展示
一、实现IP数据抓取
在Flutter中可以通过http库请求网页内容,搭配html库解析DOM节点来获取IP详情。
1. 添加依赖
在项目的pubspec.yaml文件中添加以下依赖:
dependencies: http: ^1.1.0 html: ^0.15.4
执行flutter pub get完成依赖安装。
2. 编写抓取逻辑
先定义IP数据模型,再实现网页请求与解析的函数:
import 'package:http/http.dart' as http; import 'package:html/parser.dart' as parser; import 'package:html/dom.dart' as dom; // IP详情数据模型 class IpDetails { final String ip; final String country; final String region; final String city; final String isp; IpDetails({ required this.ip, required this.country, required this.region, required this.city, required this.isp, }); } // 抓取IP详情的异步函数 Future<IpDetails?> fetchIpDetails() async { try { final response = await http.get(Uri.parse('https://ipcost.com')); if (response.statusCode == 200) { final document = parser.parse(response.body); // 注意:需根据ipcost.com实际DOM结构调整选择器,以下为示例 final ipElement = document.querySelector('div.ip-detail > span.ip-value'); final countryElement = document.querySelector('div.country-info > span.value'); final regionElement = document.querySelector('div.region-info > span.value'); final cityElement = document.querySelector('div.city-info > span.value'); final ispElement = document.querySelector('div.isp-info > span.value'); if (ipElement != null && countryElement != null && regionElement != null && cityElement != null && ispElement != null) { return IpDetails( ip: ipElement.text.trim(), country: countryElement.text.trim(), region: regionElement.text.trim(), city: cityElement.text.trim(), isp: ispElement.text.trim(), ); } } return null; } catch (e) { print('抓取失败:$e'); return null; } }
提示:打开ipcost.com的开发者工具,定位到目标数据对应的HTML元素,替换上述代码中的选择器,确保能正确解析数据。
二、在UI中展示数据
使用FutureBuilder处理异步请求,实现数据的加载状态展示:
import 'package:flutter/material.dart'; class IpInfoPage extends StatelessWidget { const IpInfoPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('我的IP详情')), body: FutureBuilder<IpDetails?>( future: fetchIpDetails(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载出错:${snapshot.error}')); } else if (snapshot.hasData && snapshot.data != null) { final ipData = snapshot.data!; return Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoItem('IP地址', ipData.ip), const SizedBox(height: 12), _buildInfoItem('国家', ipData.country), const SizedBox(height: 12), _buildInfoItem('地区', ipData.region), const SizedBox(height: 12), _buildInfoItem('城市', ipData.city), const SizedBox(height: 12), _buildInfoItem('运营商', ipData.isp), ], ), ); } else { return const Center(child: Text('未获取到IP数据')); } }, ), ); } // 封装信息行组件 Widget _buildInfoItem(String label, String value) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 80, child: Text( '$label:', style: const TextStyle(fontWeight: FontWeight.bold), ), ), Expanded(child: Text(value)), ], ); } }
三、注意事项
- 页面结构变更:如果ipcost.com更新网页布局,需重新调整DOM选择器,否则抓取逻辑会失效。
- 请求限制:频繁请求可能触发网站的反爬机制,建议添加请求间隔或本地缓存。
- 权限配置:Android需在
AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET"/>;iOS无需额外配置(目标网站为HTTPS)。
内容的提问来源于stack exchange,提问作者Esmaeil Ahmadipour
相关产品推荐
相关产品推荐

