如何在 Flutter / dart 中从网站获取数据(文本)?

How to fetch data (Text) from Website in Flutter / dart?

所以,我是 Flutter(大约一周)和 dart 的新手,但我希望这个问题不会太愚蠢:

我正在尝试为现有网站(论坛)创建应用程序。我不想使用 flutter WebView,因为我想创建一个全新的界面(该网站未针对移动视图进行优化,这就是我构建此应用程序的原因)。

(德语)论坛: https://www.porsche-914.com/forum

我想获取单个论坛主题以及帖子本身,包括用户名、标题和日期,然后将文本映射到自定义小部件以显示它。小部件部分没问题,它已经完成了,但我不知道如何从网站上获取该数据以及如何存储它。

我不知道,希望你能帮助我...

非常感谢抽出时间。

映射的工作原理:

fetched[index].title, fetched[index].text

Center(
                  child: NeumorphismPost(
                    title: fetched[index].title,
                    titleColor: Theme.of(context).cardColor,
                    textColor: Theme.of(context).cardColor,
                    text: fetched[index].text,
                    width: 370,
                    onTap: () {
                      _popupPage(context,
                          title: fetched[index].title,
                          child: Padding(
                            padding: const EdgeInsets.all(15.0),
                            child: Text(
                              fetched[index].text,
                              style: TextStyle(
                                  color: Theme.of(context).cardColor,
                                  fontSize: 18),
                            ),
                          ),
                       );
                    },
                  ),
                ),

这是我的自定义小部件:

import 'package:flutter/material.dart';

class NeumorphismPost extends StatefulWidget {
  final double width;
  final double height;
  final double borderRadius;
  final String title;
  final String text;
  final Color titleColor;
  final Color textColor;
  final double titleSize;
  final double textSize;

  final Function onTap;

  NeumorphismPost({
    this.width = 185,
    this.height = 185,
    this.title = "Title",
    this.text = "",
    this.borderRadius = 20,
    this.titleColor = const Color(0xFF424242),
    this.textColor = const Color(0xFF424242),
    this.titleSize = 22,
    this.textSize = 18,
    required this.onTap,
  });

  @override
  State<NeumorphismPost> createState() => _NeumorphismPostState();
}

class _NeumorphismPostState extends State<NeumorphismPost> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Wrap(
        direction: Axis.vertical,
        children: [
          SingleChildScrollView(
            child: SizedBox(
              height: widget.height,
              width: widget.width,
              child: GestureDetector(
                onTap: () {},
                child: Scaffold(
                  backgroundColor: Colors.transparent,
                  body: SizedBox(
                    height: widget.height,
                    width: widget.width,
                    child: Center(
                      child: Container(
                        height: widget.height,
                        width: widget.width,
                        decoration: BoxDecoration(
                          color: Theme.of(context).backgroundColor,
                          borderRadius:
                              BorderRadius.circular(widget.borderRadius),
                          boxShadow: [
                            BoxShadow(
                              color: Theme.of(context).hintColor,
                              offset: const Offset(5, 5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            ),
                            BoxShadow(
                              color: Theme.of(context).backgroundColor,
                              offset: Offset(-5, -5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            )
                          ],
                        ),
                        child: Wrap(
                          direction: Axis.horizontal,
                          children: [
                            SingleChildScrollView(
                              child: Center(
                                child: Column(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        SizedBox(
                                          height: widget.height / 3,
                                          child: Wrap(
                                            children: [
                                              Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                crossAxisAlignment:
                                                    CrossAxisAlignment.start,
                                                children: [
                                                  Padding(
                                                    padding: const EdgeInsets
                                                            .symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                    child: Text(
                                                      widget.title,
                                                      textAlign:
                                                          TextAlign.center,
                                                      overflow:
                                                          TextOverflow.fade,
                                                      style: TextStyle(
                                                        fontSize:
                                                            widget.titleSize,
                                                        fontWeight:
                                                            FontWeight.bold,
                                                        color:
                                                            widget.titleColor,
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ),
                                            ],
                                          ),
                                        ),
                                      ],
                                    ),
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        GestureDetector(
                                          onTap: () {
                                            widget.onTap();
                                          },
                                          child: Padding(
                                            padding: const EdgeInsets.symmetric(
                                                vertical: 5),
                                            child: SizedBox(
                                              height: widget.height / 1.38,
                                              child: Padding(
                                                padding:
                                                    const EdgeInsets.symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                child: Text(
                                                  widget.text,
                                                  textAlign: TextAlign.center,
                                                  style: TextStyle(
                                                    fontSize: widget.textSize,
                                                    fontWeight:
                                                        FontWeight.normal,
                                                    color: widget.textColor,
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

从我的角度来看,您想创建一个抓取工具。我检查了目标网站(https://www.porsche-914.com/forum),不需要任何特殊技术就可以抓取它(他们没有很多Ajax调用(您可以使用Postman进行测试))。所以这是一个可能的任务。我的建议流程是:

  • 使用任何技术(http、dio、inappwebview ...)加载原始 HTML
  • 使用 BeautifulSoup (https://pub.dev/packages/beautiful_soup_dart)(或任何解析器;它只是我最喜欢的解析器。)解析它。
  • 将其映射到您现有的模型。

这是一些示例代码。希望对您有所帮助:

import 'package:http/http.dart' as http;
import 'package:beautiful_soup_dart/beautiful_soup.dart';

class TestParse {
  excuteSample() async {
    var url = Uri.parse('https://www.porsche-914.com/forum');
    var response = await http.get(url);
    BeautifulSoup bs = BeautifulSoup(response.body);
    final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
    allHeaderName.forEach((element) {
      print('the header: ${element.text}');
    });
  }
}

结果如下:

你需要的最终结果是一言难尽,长代码。希望这能给你一个起点。

更新:我使用您请求的代码添加了完整的演示代码:

import 'package:beautiful_soup_dart/beautiful_soup.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(const MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final testparse = TestParse();
  List<String> yourModelPleaseReplaceThis = [];
  @override
  void initState() {
    super.initState();
    excuteRequestAndParse();
  }

  excuteRequestAndParse() async {
    final result =
        await testparse.excuteSample(); //[1] i guess you missing this await
    setState(() {
      yourModelPleaseReplaceThis = result;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) {
        return Center(
          child: NeumorphismPost(
            title: yourModelPleaseReplaceThis[index],
            titleColor: Theme.of(context).cardColor,
            textColor: Theme.of(context).cardColor,
            text: yourModelPleaseReplaceThis[index],
            width: 370,
            onTap: () {
              //THIS CODE BELOW IS YOUR CODE....
            },
          ),
        );
      },
      itemCount: yourModelPleaseReplaceThis.length,
    );
  }
}

// BELOW IS TESTING CODE....
class TestParse {
  Future<List<String>> excuteSample() async {
    var url = Uri.parse('https://www.porsche-914.com/forum');
    var response = await http.get(url);
    BeautifulSoup bs = BeautifulSoup(response.body);
    final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
    allHeaderName.forEach((element) {
      print('the header: ${element.text}');
    });
    return Future.value(allHeaderName.map((e) => e.text).toList());
  }
}

class NeumorphismPost extends StatefulWidget {
  final double width;
  final double height;
  final double borderRadius;
  final String title;
  final String text;
  final Color titleColor;
  final Color textColor;
  final double titleSize;
  final double textSize;

  final Function onTap;

  NeumorphismPost({
    this.width = 185,
    this.height = 185,
    this.title = "Title",
    this.text = "",
    this.borderRadius = 20,
    this.titleColor = const Color(0xFF424242),
    this.textColor = const Color(0xFF424242),
    this.titleSize = 22,
    this.textSize = 18,
    required this.onTap,
  });

  @override
  State<NeumorphismPost> createState() => _NeumorphismPostState();
}

class _NeumorphismPostState extends State<NeumorphismPost> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Wrap(
        direction: Axis.vertical,
        children: [
          SingleChildScrollView(
            child: SizedBox(
              height: widget.height,
              width: widget.width,
              child: GestureDetector(
                onTap: () {},
                child: Scaffold(
                  backgroundColor: Colors.transparent,
                  body: SizedBox(
                    height: widget.height,
                    width: widget.width,
                    child: Center(
                      child: Container(
                        height: widget.height,
                        width: widget.width,
                        decoration: BoxDecoration(
                          color: Theme.of(context).backgroundColor,
                          borderRadius:
                              BorderRadius.circular(widget.borderRadius),
                          boxShadow: [
                            BoxShadow(
                              color: Theme.of(context).hintColor,
                              offset: const Offset(5, 5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            ),
                            BoxShadow(
                              color: Theme.of(context).backgroundColor,
                              offset: Offset(-5, -5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            )
                          ],
                        ),
                        child: Wrap(
                          direction: Axis.horizontal,
                          children: [
                            SingleChildScrollView(
                              child: Center(
                                child: Column(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        SizedBox(
                                          height: widget.height / 3,
                                          child: Wrap(
                                            children: [
                                              Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                crossAxisAlignment:
                                                    CrossAxisAlignment.start,
                                                children: [
                                                  Padding(
                                                    padding: const EdgeInsets
                                                            .symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                    child: Text(
                                                      widget.title,
                                                      textAlign:
                                                          TextAlign.center,
                                                      overflow:
                                                          TextOverflow.fade,
                                                      style: TextStyle(
                                                        fontSize:
                                                            widget.titleSize,
                                                        fontWeight:
                                                            FontWeight.bold,
                                                        color:
                                                            widget.titleColor,
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ),
                                            ],
                                          ),
                                        ),
                                      ],
                                    ),
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        GestureDetector(
                                          onTap: () {
                                            widget.onTap();
                                          },
                                          child: Padding(
                                            padding: const EdgeInsets.symmetric(
                                                vertical: 5),
                                            child: SizedBox(
                                              height: widget.height / 1.38,
                                              child: Padding(
                                                padding:
                                                    const EdgeInsets.symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                child: Text(
                                                  widget.text,
                                                  textAlign: TextAlign.center,
                                                  style: TextStyle(
                                                    fontSize: widget.textSize,
                                                    fontWeight:
                                                        FontWeight.normal,
                                                    color: widget.textColor,
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

这是结果:

请注意:

  • 我创建的这个列表是为了示例,所以它只是一个字符串列表。您应该创建一个完整的模型。