You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中先执行网页操作再抓取目标数据?

Flutter模拟网页操作并抓取数据方案

方法一:直接分析接口发送请求(推荐,效率更高)

普通GET请求没法处理表单提交,你需要先抓包分析网站的搜索接口,再用http库模拟提交:

  1. 抓包分析请求

    • 打开浏览器按F12进入开发者工具,切换到Network标签
    • 在网页上填写出发地、到达地、日期,点击搜索按钮
    • 找到触发的POST请求,查看请求URL、请求头(Headers)和表单数据(Form Data)
    • 注意:有些网站用城市编码而非名称,表单参数要和抓包结果完全一致
  2. Flutter代码实现

import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart' as dom;

Future<void> fetchSearchData() async {
  // 替换成抓包得到的搜索接口URL
  final requestUrl = Uri.parse('https://目标网站的搜索接口');
  
  try {
    final response = await http.post(
      requestUrl,
      headers: {
        // 复制抓包得到的请求头,至少带User-Agent避免被拦截
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
        'Referer': 'https://目标网站首页URL',
      },
      body: {
        // 替换成抓包得到的表单参数
        'departure': '出发地编码',
        'destination': '到达地编码',
        'travel_date': '2024-05-20',
        'submit': '搜索',
      },
    );

    if (response.statusCode == 200) {
      // 解析返回的HTML内容
      final document = parser.parse(response.body);
      // 根据网页结构用选择器提取数据
      final resultItems = document.querySelectorAll('.result-card');
      
      for (var item in resultItems) {
        final route = item.querySelector('.route-name')?.text.trim();
        final price = item.querySelector('.price-tag')?.text.trim();
        print('路线:$route,价格:$price');
        // 把数据存入你的Flutter数据模型
      }
    } else {
      print('请求失败,状态码:${response.statusCode}');
    }
  } catch (e) {
    print('请求出错:$e');
  }
}

方法二:用WebView模拟用户操作(适合新手,无需复杂抓包)

如果不想分析接口,可以用webview_flutter库模拟手动填写表单、点击按钮,再提取数据:

  1. 添加依赖
    在pubspec.yaml中添加:
dependencies:
  webview_flutter: ^4.4.0
  1. Flutter代码实现
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'dart:convert';

class WebScrapePage extends StatefulWidget {
  const WebScrapePage({super.key});

  @override
  State<WebScrapePage> createState() => _WebScrapePageState();
}

class _WebScrapePageState extends State<WebScrapePage> {
  late WebViewController _webController;

  @override
  void initState() {
    super.initState();
    _webController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..loadRequest(Uri.parse('https://目标网站URL'))
      // 建立JS和Flutter的通信通道,传递抓取到的数据
      ..addJavaScriptChannel(
        'DataChannel',
        onMessageReceived: (JavaScriptMessage msg) {
          final List<dynamic> data = jsonDecode(msg.message);
          // 处理数据,比如更新UI或存入本地
          for (var item in data) {
            print('路线:${item['route']},价格:${item['price']}');
          }
        },
      )
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageFinished: (url) {
            // 页面加载完成后,执行JS填写表单并点击搜索
            _webController.runJavaScript('''
              // 根据网页实际元素ID/class修改选择器
              document.getElementById('departure-input').value = '北京';
              document.getElementById('destination-input').value = '上海';
              document.getElementById('date-picker').value = '2024-05-20';
              document.querySelector('.green-search-btn').click();
            ''');

            // 等待搜索结果加载,可根据实际情况调整延迟时间
            Future.delayed(const Duration(seconds: 3), () {
              // 执行JS提取数据并传给Flutter
              _webController.runJavaScript('''
                const items = document.querySelectorAll('.result-item');
                const resultData = Array.from(items).map(item => ({
                  route: item.querySelector('.route-title').textContent.trim(),
                  price: item.querySelector('.price').textContent.trim()
                }));
                DataChannel.postMessage(JSON.stringify(resultData));
              ''');
            });
          },
        ),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('模拟抓取数据')),
      body: WebViewWidget(controller: _webController),
    );
  }
}

新手注意事项

  • 抓包时要注意网站是否有反爬机制,比如需要携带Cookie或CSRF Token,这类参数需要先从首页请求中获取再提交
  • 使用WebView时,要确保网页元素的选择器(id/class)和实际网页一致,可通过浏览器F12查看元素
  • Android上如果访问HTTP网站,需要在AndroidManifest.xml中添加android:usesCleartextTraffic="true";iOS上需要在Info.plist中配置NSAppTransportSecurity

内容的提问来源于stack exchange,提问作者Huseyin A.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:25:25