MyListTest.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package space.anyi;
  2. import org.junit.jupiter.api.Test;
  3. import org.jsoup.Jsoup;
  4. import org.jsoup.nodes.Document;
  5. import space.anyi.cleaner.DetailCleaner;
  6. import space.anyi.client.GzCmcClient;
  7. import space.anyi.config.Config;
  8. import space.anyi.db.Db;
  9. import space.anyi.db.Mybatis;
  10. import space.anyi.dto.ChannelAllContentsResponse;
  11. import space.anyi.dto.NewsItem;
  12. import space.anyi.dto.NewsItemData;
  13. import space.anyi.entity.News;
  14. import space.anyi.mapper.NewsMapper;
  15. import java.time.LocalDateTime;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * 20 条数据的完整流程测试。
  20. *
  21. * <p>覆盖两个阶段的整条链路:列表采集 -> 去重入库 -> 详情抓取 -> 清洗 ->
  22. * 记者/编辑解析 -> 更新,用于快速验证全流程与可重复运行。</p>
  23. */
  24. public class MyListTest {
  25. /**
  26. * 执行 20 条的完整采集流程。
  27. *
  28. * @throws Exception 采集过程中未预期的异常
  29. */
  30. @Test
  31. public void fullCollectionFlow() throws Exception {
  32. Config config = new Config();
  33. Mybatis mybatis = new Mybatis(Db.init(config));
  34. GzCmcClient client = new GzCmcClient(config);
  35. NewsMapper mapper = mybatis.getMapper(NewsMapper.class);
  36. try {
  37. // 阶段一: 列表采集 20 条并去重入库
  38. ChannelAllContentsResponse resp = client.search(config.keywords().get(0), 1, 20);
  39. List<News> newsList = new ArrayList<>();
  40. for (NewsItem item : resp.getList()) {
  41. NewsItemData data = item.getData();
  42. if (data == null || data.getId() == null) {
  43. continue;
  44. }
  45. News news = new News();
  46. news.setId(data.getId());
  47. news.setTitle(data.getTitle());
  48. news.setUrl(data.getUrl());
  49. news.setPublishTime(LocalDateTime.parse(data.getPublishTime(), Config.TIME_FORMATTER));
  50. news.setChannelId(data.getChannelId());
  51. news.setChannelName(data.getChannelName());
  52. news.setEditor(data.getUserName());
  53. newsList.add(news);
  54. }
  55. int inserted = 0;
  56. for (News news : newsList) {
  57. if (mapper.selectById(news.getId()) == null) {
  58. mapper.insert(news);
  59. inserted++;
  60. }
  61. }
  62. System.out.printf("[20条流程] 列表采集=%d 新增入库=%d%n", newsList.size(), inserted);
  63. // 阶段二: 逐条抓详情 -> 清洗 -> 解析 -> 更新
  64. int ok = 0;
  65. for (News news : newsList) {
  66. try {
  67. String html = client.fetchDetail(news.getUrl());
  68. String content = DetailCleaner.clean(html);
  69. Document doc = Jsoup.parse(content);
  70. DetailCleaner.PersonInfo person = DetailCleaner.parsePersons(DetailCleaner.articleContentText(doc));
  71. News update = new News();
  72. update.setId(news.getId());
  73. update.setContent(content);
  74. update.setEditor(person.editor());
  75. update.setTextReporters(person.textReporters().isEmpty() ? null : String.join(",", person.textReporters()));
  76. update.setImageReporters(person.imageReporters().isEmpty() ? null : String.join(",", person.imageReporters()));
  77. update.setCorrespondents(person.correspondents().isEmpty() ? null : String.join(",", person.correspondents()));
  78. update.setContentFetchedAt(LocalDateTime.now());
  79. mapper.updateById(update);
  80. ok++;
  81. System.out.printf("[20条流程] %s 编辑=%s 文字记者=%s 图片记者=%s 通讯员=%s%n",
  82. news.getId(), person.editor(), person.textReporters(), person.imageReporters(), person.correspondents());
  83. } catch (Exception e) {
  84. System.err.printf("[20条流程] 失败 id=%s url=%s err=%s%n", news.getId(), news.getUrl(), e.getMessage());
  85. }
  86. Thread.sleep(config.sleepMs());
  87. }
  88. System.out.printf("[20条流程] 完成: 成功=%d 失败=%d%n", ok, newsList.size() - ok);
  89. } finally {
  90. mybatis.close();
  91. }
  92. }
  93. }