Prechádzať zdrojové kódy

feat:爬虫实习第四天

xiaoliu 1 týždeň pred
rodič
commit
6df8b886d5

+ 6 - 0
2026.10.22

@@ -0,0 +1,6 @@
+今日学习日报:
+学习列表接口的分页机制,根据总数与每页条数计算总页数并循环翻页至末页;
+学习同一POST接口的两种请求体构造方式,表单参数用NameValuePair+UrlEncodedFormEntity,JSON参数用StringEntity,并补充Content-Type、User-Agent请求头;
+学习HTML中内嵌JSON的提取,用正则截取subjectInfoResult、notice片段后再转为JSONObject解析;
+
+

+ 7 - 0
2026.10.23

@@ -0,0 +1,7 @@
+今日学习日报:
+学习列表接口的分页机制,根据总数与每页条数计算总页数并循环翻页至末页;
+学习同一POST接口的两种请求体构造方式,表单参数用NameValuePair+UrlEncodedFormEntity,JSON参数用StringEntity,并补充Content-Type、User-Agent请求头;
+学习HTML中内嵌JSON的提取,用正则截取subjectInfoResult、notice片段后再转为JSONObject解析;
+学习按noticeType多分支处理不同公告类型,分别取字段填充到对应的HTML模板中生成详情;
+学习时间与链接清洗,毫秒时间戳转LocalDateTime、文本日期统一为yyyy-MM-dd,并将iframe、附件、相对a/img地址重写为可访问链接;
+学习断点续采与WebMagic进阶,按DETAIL_LINK查重跳过已采数据,用HttpRequestBody.form发POST、addTargetRequest下钻详情、setSkip跳过列表页、context在列表页与详情页间传参。

+ 23 - 0
guide.md

@@ -0,0 +1,23 @@
+1. 分析构成列表查询的接口
+   - 分页控制参数
+   - 招标类型
+2. 采集详情页
+   - 构造详情页url
+   - 去重
+3. 清洗和转换
+   - HTML类型数据,考虑在原来的基础上进行精简和资源url转换
+   - json类型数据,考虑在模板HTML上填充数据
+   - 展示招标必要信息即可
+4. 入库数据构造
+   - jsoup提取html的数据
+   - json数据
+   - 正则表达式提取混在js或html属性中的数据
+5. 入库
+   - jdbc
+
+
+
+
+```mermaid
+
+```

+ 1 - 1
src/main/java/space/anyi/Application6.java

@@ -42,7 +42,7 @@ public class Application6 implements PageProcessor {
     private static final Map<String, Map<String,Object>> context = new HashMap<>();
 
     //配置
-    private Site site = new Site()
+    private Site site = new Site().setCharset(StandardCharsets.UTF_8.name())
             .setTimeOut(100 * 1000)     //超时时间
             .setRetryTimes(3)         //重试请求次数
             .setRetrySleepTime(3000)  //重试间隔时间                  请求头

+ 57 - 40
src/main/java/space/anyi/Application7.java

@@ -37,7 +37,6 @@ public class Application7 {
     static String baseUrl = "https://auct.dgggzy.cn";
     public static Pattern pattern = Pattern.compile("(\\d{4})(年|/|-|\\.)(\\d{1,2})(月|/|-|\\.)(\\d{1,2})");
 
-    static MyDao myDao = new MyDao();
     public static void main(String[] args) throws Exception {
         getList();
     }
@@ -106,27 +105,27 @@ public class Application7 {
                 //详情
                 String detailResStr = doGet(link);
 
-                Element content = Jsoup.parse(detailResStr).select("body > div.main > div > div > div.l_gpcr").first();
+//                Element content = Jsoup.parse(detailResStr).select("body > div.main > div > div > div.l_gpcr").first();
                 //文件url清洗
-                Elements as = content.select("a");
-                for (Element a : as) {
-                    a.attr("href", urlClean(a.attr("href"),baseUrl,link));
-                }
-                //图片url清洗
-                Elements imgs = content.select("img");
-                for (Element img : imgs) {
-                    img.attr("src", urlClean(img.attr("src"),baseUrl,link));
-                }
+//                Elements as = content.select("a");
+//                for (Element a : as) {
+//                    a.attr("href", urlClean(a.attr("href"),baseUrl,link));
+//                }
+//                //图片url清洗
+//                Elements imgs = content.select("img");
+//                for (Element img : imgs) {
+//                    img.attr("src", urlClean(img.attr("src"),baseUrl,link));
+//                }
                 //头部清洗
-                content.select("div.left").remove();
-                //todo:表格清洗
+//                content.select("div.left").remove();
+                //表格清洗
                 //
                 Pattern p = Pattern.compile("subjectInfoResult\\s*:\\s*(\\{[^{}]*\\})", Pattern.DOTALL);
                 Matcher m = p.matcher(detailResStr);
                 if (m.find()) {
                     JSONObject subjectInfoResult = new JSONObject(m.group(1));
                     //公告标题
-                    fcInfotitle = subjectInfoResult.get("fcInfotitle").toString();
+                    fcInfotitle = subjectInfoResult.get("fcBiddercaption").toString();
 //                    //公告开始时间
 //                    fdTradestartdate = subjectInfoResult.get("fdTradestartdate").toString();
 //                    //公告结束时间
@@ -150,7 +149,7 @@ public class Application7 {
                         fcBidComfirmation = jsonObject.get("fcInfocontent").toString();
                     }
                 }
-                String template = "<table class=\"tb02\" width=\"95%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-top: 1px solid #1d82ec\">\n" +
+                StringBuilder template = new StringBuilder("<table class=\"tb02\" width=\"95%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-top: 1px solid #1d82ec\">\n" +
                         "                      <tbody><tr style=\"border: 1px solid white;height:40px;\">\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              公告标题\n" +
@@ -163,54 +162,54 @@ public class Application7 {
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              标的编号\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fcSubjectsn\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ item.get("fcProjectsn").toString() +"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fcSubjectsn\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fcProjectsn").toString() + "</td>\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              标的名称\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fcSubjectname\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ fcSubjectname +"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fcSubjectname\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + fcSubjectname + "</td>\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              资审方式\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:viewModel.fun.getAuditType(data.subjectInfoResult.fcAudittype,viewModel.data.dictAudittypeList)\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ getAudittype(item.get("fcAudittype").toString()) +"</td>\n" +
+                        "                          <td data-bind=\"text:viewModel.fun.getAuditType(data.subjectInfoResult.fcAudittype,viewModel.data.dictAudittypeList)\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + getAudittype(item.get("fcAudittype").toString()) + "</td>\n" +
                         "                      </tr>\n" +
                         "                      <tr style=\"border: 1px solid white;height:40px;\">\n" +
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              公告开始时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fdTradestartdate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ item.get("fdTradestartdate").toString() +"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fdTradestartdate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdTradestartdate").toString() + "</td>\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              公告结束时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fdTradeenddate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ item.get("fdTradeenddate").toString() +"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fdTradeenddate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdTradeenddate").toString() + "</td>\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              报名截止时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fdAuctionapplyenddate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+ item.get("fdAuctionapplyenddate").toString() +"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fdAuctionapplyenddate\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdAuctionapplyenddate").toString() + "</td>\n" +
                         "                      </tr>\n" +
                         "                      <tr style=\"border: 1px solid white;height:40px;\">\n" +
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              保证金(元)\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:showNo(numToCurrency(data.subjectInfoResult.fmDepositamt))\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+item.get("fmDepositamt").toString()+"</td>\n" +
+                        "                          <td data-bind=\"text:showNo(numToCurrency(data.subjectInfoResult.fmDepositamt))\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fmDepositamt").toString() + "</td>\n" +
                         "\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              保证金截止时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:showNo(data.subjectInfoResult.fdDepositendtime)\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+item.get("fdDepositendtime").toString()+"</td>\n" +
+                        "                          <td data-bind=\"text:showNo(data.subjectInfoResult.fdDepositendtime)\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdDepositendtime").toString() + "</td>\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              报价开始时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fdListingstarttime\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+item.get("fdListingstarttime").toString()+"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fdListingstarttime\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdListingstarttime").toString() + "</td>\n" +
                         "                      </tr>\n" +
                         "                      <tr style=\"border: 1px solid white;height:40px;\">\n" +
                         "                          <td style=\"width:13%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              报价截止时间\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fdListingendtime\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+item.get("fdListingendtime").toString()+"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fdListingendtime\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + item.get("fdListingendtime").toString() + "</td>\n" +
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">\n" +
                         "                              交易方式\n" +
                         "                          </td>\n" +
-                        "                          <td data-bind=\"text:data.subjectInfoResult.fcTrademethod\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">"+getTradeMethod(item.get("fcTrademethod").toString())+"</td>\n" +
+                        "                          <td data-bind=\"text:data.subjectInfoResult.fcTrademethod\" style=\"width:20%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\">" + getTradeMethod(item.get("fcTrademethod").toString()) + "</td>\n" +
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\"></td>\n" +
                         "                          <td style=\"width:14%;background: white;border: 1px solid #FF9E0D;margin-bottom: 10px;\"></td>\n" +
                         "                      </tr>\n" +
@@ -250,10 +249,11 @@ public class Application7 {
                         "                              </table>\n" +
                         "                          </td>\n" +
                         "                      </tr>\n" +
-                        "                  </tbody></table>";
-                content = Jsoup.parse(template);
+                        "                  </tbody></table>");
+//                content = Jsoup.parse(template.toString());
                 fcBidComfirmation = Parser.unescapeEntities(fcBidComfirmation, false).replace("\\\"", "\"");
-                content.appendChild(Jsoup.parse(fcBidComfirmation));
+//                content.appendChild(Jsoup.parse(fcBidComfirmation));
+                template.append(Parser.unescapeEntities(fcBidComfirmation, false).replace("\\\"", "\""));
                 //标的详细信息
 //                element = content.select("span[data-bind=text:data.subjectInfoResult.fcSubjectdetails]").first();
 //                if (Objects.isNull(element)) element = content.select("td[data-bind=text:data.subjectInfoResult.fcSubjectdetails]").first();
@@ -269,37 +269,54 @@ public class Application7 {
 //                    fcBidComfirmation = Parser.unescapeEntities(fcBidComfirmation, false).replace("\\\"", "\"");
 //                    element.appendChild(Jsoup.parse(fcBidComfirmation));
 //                }
-                //todo:附件
+                //附件
                 p = Pattern.compile("fileList\\s*:\\s*ko\\.observableArray\\(\\s*(\\[[\\s\\S]*?\\])\\s*\\)");
                 m = p.matcher(detailResStr);
                 if (m.find()) {
                     JSONArray fileList = new JSONArray(m.group(1));
                     for (int j = 0; j < fileList.length(); j++) {
                         JSONObject file = fileList.getJSONObject(j);
-                        String fileId = file.get("id").toString();
-                        String fcFilename = file.get("fcFilename").toString();
-                        String fileUrl = String.format(fileDownloadUrl, fileId);
-                        Element element = Jsoup.parse(String.format("<div>点击查看公告内容:<a href='%s'>%s</a></div>", fileUrl, fcFilename));
-                        content.appendChild(element);
+                        template.append(String.format("<div>点击查看公告内容:<a href='%s'>%s</a></div>", String.format(fileDownloadUrl, file.get("id").toString()), file.get("fcFilename").toString()));
                     }
                 }
                 //报价
+                StringBuilder table = new StringBuilder("                      <table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" class=\"table_list table02\"\n" +
+                        "                             style=\"border-collapse: collapse;font-size: 12pt;margin-bottom: 10px;width:100%;margin-left: 15px ; border: 1px solid #FF9E0D;\">\n" +
+                        "                          <thead>\n" +
+                        "                              <tr style=\"background-color: #FF6600\">\n" +
+                        "                                  <th style=\"width:10%;text-align:center;color: white;background-color: #FC7979\">序号</th>\n" +
+                        "                                  <th style=\"width:10%;text-align:center;color: white;background-color: #FC7979\">竞拍号\n" +
+                        "                                  </th>\n" +
+                        "                                  <th style=\"width:45%;text-align:center;color: white;background-color: #FC7979\">报价</th>\n" +
+                        "                                  <th style=\"width:25%;text-align:center;color: white;background-color: #FC7979\">报价时间\n" +
+                        "                                  </th>\n" +
+                        "                              </tr>\n" +
+                        "                          </thead>\n" +
+                        "                          <tbody id=\"dataBindId3\" data-bind='foreach: viewModel.data.priceList'>\n");
                 p = Pattern.compile("priceList\\s*:\\s*ko\\.observableArray\\(\\s*(\\[[\\s\\S]*?\\])\\s*\\)");
                 m = p.matcher(detailResStr);
                 if (m.find()) {
                     JSONArray priceList = new JSONArray(m.group(1));
                     for (int j = 0; j < priceList.length(); j++) {
                         JSONObject jsonObject = priceList.getJSONObject(j);
-                        String orderNum = jsonObject.get("orderNum").toString();
-                        String fnAuctionapplyno = jsonObject.get("fnAuctionapplyno").toString();
+                        String tr = "  <tr>\n" +
+                                "                                  <td style=\"text-align:center\" data-bind=\"text:orderNum\">"+jsonObject.get("orderNum").toString()+"</td>\n" +
+                                "                                  <td style=\"text-align:center\" data-bind=\"text: fnAuctionapplyno\">"+jsonObject.get("fnAuctionapplyno").toString()+"</td>\n" +
+                                "                                  <td style=\"text-align: center;max-width: 30px\" data-bind=\"text: fmAuctionprice\">"+jsonObject.get("fmAuctionprice").toString()+"</td>\n" +
+                                "                                  <td style=\"text-align: center;max-width: 100px;text-align:center;\"\n" +
+                                "                                      data-bind=\"text: fdAuctionpricedate\">"+jsonObject.get("fdAuctionpricedate").toString()+"</td>\n" +
+                                "                              </tr>";
+                        table.append(tr);
                     }
                 }
+                table.append(" </tbody>\n" + "                      </table>");
+                template.append(table);
                 //save
                 //字段:ID,SOURCE_NAME(网站名称),DETAIL_LINK(详情链接),DETAIL_TITLE(详情标题),DETAIL_CONTENT(正文HTML),PAGE_TIME(列表时间),CREATE_TIME(创建时间),LIST_TITLE(列表标题),CREATE_BY(创建者名称)
                 String SOURCE_NAME = "东莞市公共资源交易中心";
                 String DETAIL_LINK = link;
                 String DETAIL_TITLE = fcSubjectname;
-                String DETAIL_CONTENT = content.toString();
+                String DETAIL_CONTENT = template.toString();
                 String dateStr = item.get("fdTradestartdate").toString();
                 Matcher matcher = pattern.matcher(dateStr);
                 if (matcher.find()) {
@@ -323,7 +340,7 @@ public class Application7 {
                     preparedStatement.setDate(6, Date.valueOf(CREATE_TIME));
                     preparedStatement.setString(7, LIST_TITLE);
                     preparedStatement.setString(8, CREATE_BY);
-//                    preparedStatement.executeUpdate();
+                    preparedStatement.executeUpdate();
                 }
             }
 
@@ -374,7 +391,7 @@ public class Application7 {
         List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
         parameters.add(new BasicNameValuePair("pagesize",pageSize+""));
         parameters.add(new BasicNameValuePair("currentpage",index+""));
-        parameters.add(new BasicNameValuePair("search","{\"startDate\":\"\",\"endDate\":\"\",\"extVal\":\"\",\"extVal2\":\"\",\"extVal3\":\"\",\"extVal4\":\"\",\"extVal5\":\"\",\"extVal6\":-999999,\"extVal7\":-999999,\"extVal8\":null,\"extVal9\":\"02\",\"extVal10\":null,\"extVal11\":null,\"extVal12\":null,\"extVal13\":null,\"extVal14\":null,\"extVal15\":null,\"extVal16\":null,\"orderField\":\"\",\"orderType\":\"\",\"name\":\"\",\"code\":\"\"}"));
+        parameters.add(new BasicNameValuePair("search","{\"startDate\":\"\",\"endDate\":\"\",\"extVal\":\"\",\"extVal2\":\"\",\"extVal3\":\"\",\"extVal4\":\"\",\"extVal5\":\"\",\"extVal6\":-999999,\"extVal7\":-999999,\"extVal8\":null,\"extVal9\":\"02\",\"extVal10\":null,\"extVal11\":null,\"extVal12\":null,\"extVal13\":null,\"extVal14\":null,\"extVal15\":null,\"extVal16\":null,\"orderField\":\"\",\"orderType\":\"desc\",\"name\":\"\",\"code\":\"\"}"));
 
         // 构造一个form表单式的实体
         UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);

+ 641 - 0
src/main/java/space/anyi/Application8.java

@@ -0,0 +1,641 @@
+package space.anyi;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.jsoup.parser.Parser;
+
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Application8 {
+    static String indexUrl = "https://www.ymzec.com/bid-api/api/truelore-business-support/noauth/trans/trade/pageEs";
+    static String detailUrl = "https://www.ymzec.com/bid-api/api/truelore-business-support/noauth/trans/trade/getByTradeId?id=%s&noticeType=%d";
+    static String detailHtmlUrl = "https://www.ymzec.com/bid/web-outportal/index.html#/trade-info-detail?id=%s&noticeType=%d";
+    static String baseUrl = "https://www.ymzec.com";
+    public static Pattern pattern = Pattern.compile("(\\d{4})(年|/|-|\\.)(\\d{1,2})(月|/|-|\\.)(\\d{1,2})");
+
+    public static void main(String[] args) throws Exception {
+        getList();
+    }
+
+    static int total = 1;
+    static int index = 1;
+    static int pageSize = 10;
+    static int count = 0;
+    public static void getList() throws Exception {
+        while (true){
+            //列表url构建
+            String listUrl = indexUrl;
+            System.out.println(listUrl);
+            //采集列表页
+            String res = doPost(indexUrl);
+            //采集总页数
+            JSONObject response = new JSONObject(res).getJSONObject("data");
+            total = response.getInt("totalCount");
+
+            JSONArray items = response.getJSONArray("list");
+            for (int i = 0; i < items.length(); i++) {
+                count++;
+                JSONObject item = items.getJSONObject(i);
+
+                String id = item.get("id").toString();
+                //标的名称
+                String businessName = item.get("businessName").toString();
+                int noticeType = item.getInt("noticeType");
+                LocalDateTime releaseTime = Instant.ofEpochMilli(Long.parseLong(item.get("releaseTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime();
+
+                String link = String.format(detailUrl, id,noticeType);
+                System.out.println(businessName);
+                System.out.println(link);
+                //数据库是否已存在
+                String querySql = "select DETAIL_LINK from XIN_XI_INFO_TEST where DETAIL_LINK = ?";
+                try(Connection connection = MyDao.getConnection();
+                    PreparedStatement prepareStatement = connection.prepareStatement(querySql);){
+                    prepareStatement.setString(1,link);
+                    ResultSet resultSet = prepareStatement.executeQuery();
+                    if (resultSet.next()) {
+                        System.out.println("跳过" + link);
+                        resultSet.close();
+                        continue;
+                    }
+                    resultSet.close();
+                }
+                //详情
+                String detailResStr = doGet(link);
+                JSONObject detailResponse = new JSONObject(detailResStr).getJSONObject("data");
+                JSONObject detail = new JSONObject();
+                StringBuilder template = new StringBuilder();
+                String detailBusinessName = "";
+                switch (noticeType){
+                    case 1:
+                        detail = detailResponse.getJSONObject("biddingNotice");
+                        detailBusinessName = detail.get("businessName").toString();
+                        template = new StringBuilder("<div data-v-133901b8=\"\" class=\"template-container customize\">\n" +
+                                "\t<div data-v-133901b8=\"\" class=\"title-container\">\n" +
+                                "\t\t<div data-v-133901b8=\"\">\n" +
+                                "\t\t\t<div data-v-133901b8=\"\" class=\"title-container-top\">\n" +
+                                "\t\t\t\t<p data-v-133901b8=\"\" class=\"detail-title\">\n" +
+                                "\t\t\t\t\t<span data-v-133901b8=\"\" class=\"el-tooltip\" aria-describedby=\"el-tooltip-8937\" tabindex=\"0\">\n" +
+                                "\t\t\t\t\t\t"+ detailBusinessName +"\n" +
+                                "\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t</p>\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t\t<div data-v-133901b8=\"\" class=\"title-container-middle\">\n" +
+                                "\t\t\t\t<span data-v-133901b8=\"\" class=\"el-tag el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t\t采购方式:"+detail.get("purchaseModeName").toString()+"\n" +
+                                "\t\t\t\t</span>\n" +
+                                "\t\t\t\t<span data-v-133901b8=\"\" class=\"el-tag el-tag--warning el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t\t项目类型:"+detail.get("purchaseProjectTypeName").toString()+"\n" +
+                                "\t\t\t\t</span>\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t\t<div data-v-133901b8=\"\" class=\"title-container-bottom\">\n" +
+                                "\t\t\t\t<div data-v-133901b8=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t<div data-v-133901b8=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t<p data-v-133901b8=\"\">\n" +
+                                "\t\t\t\t\t\t\t发布时间:\n" +
+                                "\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t<p data-v-133901b8=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t"+ releaseTime +"\n" +
+                                "\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t</div>\n" +
+                                "\t\t\t\t<div data-v-133901b8=\"\" class=\"customize-bid-item customize-bid-item-more\">\n" +
+                                "\t\t\t\t\t<div data-v-133901b8=\"\" class=\"content-title\">\n" +
+                                "\t\t\t\t\t\t<div data-v-133901b8=\"\" class=\"content-title-left\">\n" +
+                                "\t\t\t\t\t\t\t<p data-v-133901b8=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t"+detail.get("purchaseProjectName")+"\n" +
+                                "\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t<span data-v-133901b8=\"\" class=\"bid-tab-ketou\">\n" +
+                                "\t\t\t\t\t\t\t\t可投\n" +
+                                "\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-133901b8=\"\" class=\"content-title\">\n" +
+                                "\t\t\t\t\t\t<div data-v-133901b8=\"\" class=\"content-title-left\">\n" +
+                                "\t\t\t\t\t\t\t<p data-v-133901b8=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t标段编号:"+detail.get("bidSectionCode")+"\n" +
+                                "\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t</div>\n" +
+                                "\t\t\t\t<!---->\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t</div>\n" +
+                                "\t</div>\n" +
+                                "\t<div data-v-133901b8=\"\" class=\"content-container content-margin\">\n" +
+                                "\t\t<!---->\n" +
+                                "\t\t<div data-v-133901b8=\"\" class=\"content-part\">\n" +
+                                "\t\t\t<iframe data-v-133901b8=\"\" id=\"pdfIframe\" src=\""+ detail.get("htmlFileUrl")+"\" allowfullscreen=\"allowfullscreen\" frameborder=\"0\" style=\"margin-top: 20px; width: 100%; height: 500px;\">\n" +
+                                "\t\t\t</iframe>\n" +
+                                "\t\t</div>\n" +
+                                "\t</div>\n");
+
+                        break;
+                    case 2:
+                        detail = detailResponse.getJSONObject("biddingChangeNotice");
+                        detailBusinessName = detail.get("businessName").toString();
+                        JSONObject changeContent = detail.getJSONObject("changeContent");
+                        template = new StringBuilder("<div data-v-7fb3b652=\"\" class=\"template-container customize\">\n" +
+                                "\t<div data-v-7fb3b652=\"\" class=\"title-container\">\n" +
+                                "\t\t<div data-v-7fb3b652=\"\" class=\"title-container-top\">\n" +
+                                "\t\t\t<p data-v-7fb3b652=\"\" class=\"detail-title\">\n" +
+                                "\t\t\t\t<span data-v-7fb3b652=\"\" class=\"el-tooltip\" aria-describedby=\"el-tooltip-7898\" tabindex=\"0\">\n" +
+                                "\t\t\t\t\t"+detailBusinessName+"\n" +
+                                "\t\t\t\t</span>\n" +
+                                "\t\t\t</p>\n" +
+                                "\t\t</div>\n" +
+                                "\t\t<div data-v-7fb3b652=\"\" class=\"title-container-middle\">\n" +
+                                "\t\t\t<span data-v-7fb3b652=\"\" class=\"el-tag el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t采购方式:"+detail.get("purchaseModeName")+"\n" +
+                                "\t\t\t</span>\n" +
+                                "\t\t\t<span data-v-7fb3b652=\"\" class=\"el-tag el-tag--warning el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t项目类型:"+detail.get("purchaseProjectTypeName")+"\n" +
+                                "\t\t\t</span>\n" +
+                                "\t\t</div>\n" +
+                                "\t\t<div data-v-7fb3b652=\"\" class=\"title-container-bottom\">\n" +
+                                "\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t<p data-v-7fb3b652=\"\">\n" +
+                                "\t\t\t\t\t\t发布时间:\n" +
+                                "\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t"+releaseTime+"\n" +
+                                "\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t</div>\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t\t<div data-v-7fb3b652=\"\" class=\"customize-bid-item customize-bid-item-more\">\n" +
+                                "\t\t\t\t<div data-v-7fb3b652=\"\" class=\"content-title\">\n" +
+                                "\t\t\t\t\t"+detail.get("purchaseProjectName")+"\n" +
+                                "\t\t\t\t\t<span data-v-7fb3b652=\"\" class=\"code-name\">\n" +
+                                "\t\t\t\t\t\t"+detail.get("bidSectionCode")+"\n" +
+                                "\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t</div>\n" +
+                                "\t\t\t\t<div data-v-7fb3b652=\"\" class=\"item-container\" style=\"margin-top: 16px;\">\n" +
+                                "\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content-title\">\n" +
+                                "\t\t\t\t\t\t标段最新时间\n" +
+                                "\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"content-part\">\n" +
+                                "\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t标段/包名称:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+ changeContent.get("bidSectionName")+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t标段/包编号:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+changeContent.get("bidSectionCode")+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t文件获取开始时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t文件获取截止时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(changeContent.get("tenderDocGetEndTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t供应商提问截止时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t截标/开标时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(changeContent.get("bidEndTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t报名开始时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t报名截止时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-row\">\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t文件递交截止时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(changeContent.get("tenderDocSubmitEndTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t<div data-v-7fb3b652=\"\" class=\"el-col el-col-12\">\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"name\">\n" +
+                                "\t\t\t\t\t\t\t\t\t异议提出截止时间:\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t\t<p data-v-7fb3b652=\"\" class=\"content\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(changeContent.get("dissentEndTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</p>\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t</div>\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t</div>\n" +
+                                "\t\t<!---->\n" +
+                                "\t</div>\n" +
+                                "\t<div data-v-7fb3b652=\"\" class=\"content-container\">\n" +
+                                "\t\t<!---->\n" +
+                                "\t\t<div data-v-7fb3b652=\"\" class=\"content-part\">\n" +
+                                "\t\t\t<iframe data-v-7fb3b652=\"\" id=\"pdfIframe\" src=\"https%3A%2F%2Fwww.ymzec.com%2Fbid-api%2Foss-ymz-prd-bc-bidbase%2F1252684541891436545%2F2%2F2026%2F10%2F21%2F1562396160526450688%2F1562396160534839297%2F%25E9%2594%25A6%25E5%25B7%259E%25E7%259F%25B3%25E5%258C%2596%25E5%2588%2586%25E5%2585%25AC%25E5%258F%25B82026%25E8%2587%25B32027%25E5%25B9%25B4%25E5%25BA%25A6%25E6%25B5%25B7%25E4%25B8%258A%25E5%258E%259F%25E6%25B2%25B9%25E8%25BF%2590%25E8%25BE%2593%25E6%259C%258D%25E5%258A%25A1%25E6%25A1%2586%25E6%259E%25B61.0.3.20261021%25E5%2585%25AC%25E5%2591%258A%2528%25E9%2582%2580%25E8%25AF%25B7%25E5%2587%25BD%2529.pdf%3Fresponse-content-disposition%3Dattachment%253Bfilename%253D%2525E9%252594%2525A6%2525E5%2525B7%25259E%2525E7%25259F%2525B3%2525E5%25258C%252596%2525E5%252588%252586%2525E5%252585%2525AC%2525E5%25258F%2525B82026%2525E8%252587%2525B32027%2525E5%2525B9%2525B4%2525E5%2525BA%2525A6%2525E6%2525B5%2525B7%2525E4%2525B8%25258A%2525E5%25258E%25259F%2525E6%2525B2%2525B9%2525E8%2525BF%252590%2525E8%2525BE%252593%2525E6%25259C%25258D%2525E5%25258A%2525A1%2525E6%2525A1%252586%2525E6%25259E%2525B61.0.3.20261021%2525E5%252585%2525AC%2525E5%252591%25258A%252528%2525E9%252582%252580%2525E8%2525AF%2525B7%2525E5%252587%2525BD%252529.pdf%26X-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Date%3D20261022T054514Z%26X-Amz-SignedHeaders%3Dhost%26X-Amz-Expires%3D1800%26X-Amz-Credential%3D6w2sulE5ALA2bxEW%252F20261022%252Fcn-north-1%252Fs3%252Faws4_request%26X-Amz-Signature%3D85f7a798fefcf32c334fbc0877944651314bfa5c908aabecf2e86715d58a841c\" allowfullscreen=\"allowfullscreen\" frameborder=\"0\" style=\"margin-top: 20px; width: 100%; height: 500px;\">\n" +
+                                "\t\t\t</iframe>\n" +
+                                "\t\t</div>\n" +
+                                "\t</div>\n" +
+                                "</div>");
+
+                        break;
+                    case 3:
+                        detail = detailResponse.getJSONObject("bidCandidateAnnounces");
+                        detailBusinessName = detail.get("businessName").toString();
+                        template = new StringBuilder("<div data-v-b4fad760=\"\">\n" +
+                                "\t<div data-v-b4fad760=\"\" class=\"title-container\">\n" +
+                                "\t\t<div data-v-b4fad760=\"\" class=\"title-container-middle\">\n" +
+                                "\t\t\t<span data-v-b4fad760=\"\" class=\"el-tag el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t采购方式:公开招标\n" +
+                                "\t\t\t</span>\n" +
+                                "\t\t\t<span data-v-b4fad760=\"\" class=\"el-tag el-tag--warning el-tag--small el-tag--light\">\n" +
+                                "\t\t\t\t项目类型:服务类\n" +
+                                "\t\t\t</span>\n" +
+                                "\t\t</div>\n" +
+                                "\t\t<div data-v-b4fad760=\"\" class=\"title-container-bottom\">\n" +
+                                "\t\t\t<div data-v-1b67d0d5=\"\" data-v-b4fad760=\"\">\n" +
+                                "\t\t\t\t<form data-v-1b67d0d5=\"\" class=\"el-form dynamic-form el-form--label-left\">\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"noticeName\" style=\"width: 50%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t公示名称:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+detailBusinessName+"\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"industrySort\" style=\"width: 50%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t所属行业分类:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"startTime\" style=\"width: 50%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t公示开始时间:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(detail.get("startTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"endTime\" style=\"width: 50%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t公示结束时间:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t"+Instant.ofEpochMilli(Long.parseLong(detail.get("endTime").toString())).atZone(ZoneId.systemDefault()).toLocalDateTime()+"\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"bidEvaluationInfo\" style=\"width: 100%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t评标情况:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t<div data-v-6b4b44e0=\"\" data-v-1b67d0d5=\"\" class=\"dynamic-form-item\" data-key=\"remarks\" style=\"width: 50%;\">\n" +
+                                "\t\t\t\t\t\t<div data-v-6b4b44e0=\"\" class=\"el-form-item formItemRef is-no-asterisk el-form-item--small\">\n" +
+                                "\t\t\t\t\t\t\t<label class=\"el-form-item__label\" style=\"width: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t备注:\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</label>\n" +
+                                "\t\t\t\t\t\t\t<div class=\"el-form-item__content\" style=\"margin-left: 150px;\">\n" +
+                                "\t\t\t\t\t\t\t\t<span data-v-6b4b44e0=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t\t--\n" +
+                                "\t\t\t\t\t\t\t\t</span>\n" +
+                                "\t\t\t\t\t\t\t\t<!---->\n" +
+                                "\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t</form>\n" +
+                                "\t\t\t</div>\n" +
+                                "\t\t</div>\n" +
+                                "\t</div>\n" +
+                                "</div>");
+                        //
+                        template.append("<div data-v-b4fad760=\"\" style=\"font-size: 16px; font-weight: 700; margin-bottom: 10px;\">\n" +
+                                "\t\t\t标段/包名称:"+businessName+"\n" +
+                                "\t\t</div>\n" +
+                                "\t\t<div data-v-b4fad760=\"\" style=\"font-size: 16px; font-weight: 700; margin-bottom: 10px;\">\n" +
+                                "\t\t\t标段/包编号:"+detail.get("bidSectionCode")+"\n" +
+                                "\t\t</div>");
+                        //todo:标段/包信息
+                        JSONArray bidInfoForPlatFormDTOList = detail.getJSONArray("bidInfoForPlatFormDTOList");
+                        template.append("<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"el-table__header\" style=\"width: 1255px;\">\n" +
+                                "\t\t\t\t\t\t<thead class=\"has-gutter\">\n" +
+                                "\t\t\t\t\t\t\t<tr class=\"\">\n" +
+                                "\t\t\t\t\t\t\t\t<th colspan=\"1\" rowspan=\"1\" class=\"el-table_1_column_1     is-leaf el-table__cell\" style=\"background-color: rgb(243, 244, 247);\">\n" +
+                                "\t\t\t\t\t\t\t\t\t<div class=\"cell\">\n" +
+                                "\t\t\t\t\t\t\t\t\t\t项目类型\n" +
+                                "\t\t\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t\t</th>\n" +
+                                "\t\t\t\t\t\t\t\t<th colspan=\"1\" rowspan=\"1\" class=\"el-table_1_column_2     is-leaf el-table__cell\" style=\"background-color: rgb(243, 244, 247);\">\n" +
+                                "\t\t\t\t\t\t\t\t\t<div class=\"cell\">\n" +
+                                "\t\t\t\t\t\t\t\t\t\t采购/招标方式\n" +
+                                "\t\t\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t\t</th>\n" +
+                                "\t\t\t\t\t\t\t\t<th colspan=\"1\" rowspan=\"1\" class=\"el-table_1_column_3     is-leaf el-table__cell\" style=\"background-color: rgb(243, 244, 247);\">\n" +
+                                "\t\t\t\t\t\t\t\t\t<div class=\"cell\">\n" +
+                                "\t\t\t\t\t\t\t\t\t\t中标形式\n" +
+                                "\t\t\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t\t</th>\n" +
+                                "\t\t\t\t\t\t\t\t<th colspan=\"1\" rowspan=\"1\" class=\"el-table_1_column_4     is-leaf el-table__cell\" style=\"background-color: rgb(243, 244, 247);\">\n" +
+                                "\t\t\t\t\t\t\t\t\t<div class=\"cell\">\n" +
+                                "\t\t\t\t\t\t\t\t\t\t评标时间\n" +
+                                "\t\t\t\t\t\t\t\t\t</div>\n" +
+                                "\t\t\t\t\t\t\t\t</th>\n" +
+                                "\t\t\t\t\t\t\t\t<th class=\"el-table__cell gutter\" style=\"width: 0px; display: none;\">\n" +
+                                "\t\t\t\t\t\t\t\t</th>\n" +
+                                "\t\t\t\t\t\t\t</tr>\n" +
+                                "\t\t\t\t\t\t</thead>\n" +
+                                "                        <tbody>");
+//                        Objects.
+                        //中标候选人
+                        JSONArray candidates = detail.getJSONArray("candidates");
+                        //非中标候选人评审情况
+                        JSONArray notCandidates = detail.getJSONArray("notCandidates");
+                        break;
+                    default:
+                        System.err.println(String.format("未处理的通知类型:%d", noticeType));
+                        continue;
+                }
+                //附件
+                JSONArray announceFileDtoList = detail.getJSONArray("announceFileDtoList");
+                if (Objects.nonNull(announceFileDtoList)) {
+                    template.append("公告附件:");
+                    for (int j = 0; j < announceFileDtoList.length(); j++) {
+                        JSONObject jsonObject = announceFileDtoList.getJSONObject(j);
+                        template.append(String.format("<div>点击内容:<a href='%s'>%s</a></div>", jsonObject.get("downLoadUrl"),jsonObject.get("fileName")));
+                    }
+                }
+                JSONArray remarksFileDtoList = detail.getJSONArray("remarksFileDtoList");
+                if (Objects.nonNull(remarksFileDtoList)) {
+                    template.append("其他附件:");
+                    for (int j = 0; j < remarksFileDtoList.length(); j++) {
+                        JSONObject jsonObject = remarksFileDtoList.getJSONObject(j);
+                        template.append(String.format("<div>点击内容:<a href='%s'>%s</a></div>", jsonObject.get("downLoadUrl"),jsonObject.get("fileName")));
+                    }
+                }
+                //招标单位
+                template.append(String.format("招标人:%s-%s-%s", detail.get("tendererName").toString(),detail.get("contactPerson").toString(),detail.get("contactNumber").toString()));
+                //save
+                //字段:ID,SOURCE_NAME(网站名称),DETAIL_LINK(详情链接),DETAIL_TITLE(详情标题),DETAIL_CONTENT(正文HTML),PAGE_TIME(列表时间),CREATE_TIME(创建时间),LIST_TITLE(列表标题),CREATE_BY(创建者名称)
+                String SOURCE_NAME = "中国石油采购与招标网";
+                String DETAIL_LINK = String.format(detailHtmlUrl, id,noticeType);
+                String DETAIL_TITLE = detailBusinessName;
+                String DETAIL_CONTENT = template.toString();
+                LocalDate PAGE_TIME = releaseTime.toLocalDate();
+                LocalDate CREATE_TIME = LocalDate.now();
+                String LIST_TITLE = businessName;
+                String CREATE_BY = "黄略";
+
+                String sql = "insert into " + MyDao.TABLE_NAME +"(SOURCE_NAME,DETAIL_LINK,DETAIL_TITLE,DETAIL_CONTENT,PAGE_TIME,CREATE_TIME,LIST_TITLE,CREATE_BY) VALUES (?,?,?,?,?,?,?,?)";
+                try(Connection connection = MyDao.getConnection();
+                    PreparedStatement preparedStatement = connection.prepareStatement(sql);){
+                    preparedStatement.setString(1, SOURCE_NAME);
+                    preparedStatement.setString(2, DETAIL_LINK);
+                    preparedStatement.setString(3, DETAIL_TITLE);
+                    preparedStatement.setString(4, DETAIL_CONTENT);
+                    preparedStatement.setDate(5, Date.valueOf(PAGE_TIME));   // LocalDate -> java.sql.Date
+                    preparedStatement.setDate(6, Date.valueOf(CREATE_TIME));
+                    preparedStatement.setString(7, LIST_TITLE);
+                    preparedStatement.setString(8, CREATE_BY);
+//                    preparedStatement.executeUpdate();
+                }
+            }
+
+            if (index<= (total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1)) {
+                index++;
+            }else {
+                break;
+            }
+            //先只处理一页
+            break;
+        }
+        System.out.println(count);
+    }
+
+
+    public static String doGet(String url) throws Exception {
+        String result = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet httpGet = new HttpGet(url);
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(10 * 1000).setSocketTimeout(60 * 1000)
+                .build();
+        httpGet.setConfig(requestConfig);
+        CloseableHttpResponse response = null;
+        try {
+            response = httpClient.execute(httpGet);
+            if (response.getStatusLine().getStatusCode() == 200) {
+                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
+                result = content;
+            }
+        } finally {
+            if (response != null) {
+                response.close();
+            }
+            httpClient.hashCode();
+        }
+        return result;
+    }
+
+    public static String doPost(String path) throws Exception {
+        String result = "";
+
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        // 创建http POST请求
+        HttpPost httpPost = new HttpPost(path);
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(10 * 1000).setSocketTimeout(60 * 1000)
+                .build();
+        httpPost.setConfig(requestConfig);
+//        List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
+//        parameters.add(new BasicNameValuePair("pagesize",pageSize+""));
+//        parameters.add(new BasicNameValuePair("currentpage",index+""));
+//        parameters.add(new BasicNameValuePair("search","{\"startDate\":\"\",\"endDate\":\"\",\"extVal\":\"\",\"extVal2\":\"\",\"extVal3\":\"\",\"extVal4\":\"\",\"extVal5\":\"\",\"extVal6\":-999999,\"extVal7\":-999999,\"extVal8\":null,\"extVal9\":\"02\",\"extVal10\":null,\"extVal11\":null,\"extVal12\":null,\"extVal13\":null,\"extVal14\":null,\"extVal15\":null,\"extVal16\":null,\"orderField\":\"\",\"orderType\":\"desc\",\"name\":\"\",\"code\":\"\"}"));
+
+        // 构造一个form表单式的实体
+        String json = String.format("{\"pageNum\":%d,\"pageSize\":%d,\"releaseEndTime\":\"\",\"releaseStartTime\":\"\",\"purchaseProjectType\":\"\",\"purchaseModes\":[],\"purchasePatternId\":\"\",\"tendererName\":\"\",\"noticeTypes\":[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"8\",\"9\",\"10\",\"15\",\"16\",\"17\",\"21\",\"22\"]}", index, pageSize);
+        StringEntity entity = new StringEntity(json,ContentType.APPLICATION_JSON);
+//        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
+        // 将请求实体设置到httpPost对象中
+        httpPost.setEntity(entity);
+        httpPost.setHeader("Content-Type", "application/json");
+        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
+        CloseableHttpResponse response = null;
+        try {
+            response = httpclient.execute(httpPost);
+            if (response.getStatusLine().getStatusCode() == 200) {
+                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
+                return content;
+            }
+        } finally {
+            if (response != null) {
+                response.close();
+            }
+            httpclient.close();
+        }
+        return result;
+    }
+
+    public static String urlClean(String url,String baseUrl,String currentUrl){
+        if (url.startsWith("http")) {
+            return url;
+        }
+        String result = "";
+        if (url.startsWith("/")) {
+            //根路径开始
+            result = baseUrl + url;
+        }else if (url.startsWith("./")){
+            //当前同级目录
+            result = currentUrl.substring(0, currentUrl.lastIndexOf("/")) + url.substring(url.indexOf("./") + 1);
+        }else if (url.startsWith("../")){
+            //多级目录,取最后的uri拼接到baseUrl,等价于所有 "../" 替换成 "/"
+            result = baseUrl + url.substring(url.lastIndexOf("../") + 2);
+        }else {
+            //等价于当前目录
+            result = currentUrl.substring(0,currentUrl.lastIndexOf("/") + 1) + url;
+        }
+        return result;
+    }
+
+
+    public static String getNoticeType(int val){
+        switch (val){
+            case 1:
+                return "公告";
+            case 2:
+                return "变更公告";
+            case 3:
+                return "中标候选人/拟成交结果公示";
+            case 4:
+                return "中标/成交结果公告";
+            case 5:
+                return "招标/采购异常";
+            case 8:
+                return "候选人变更公告";
+            case 9:
+                return "中标/成交结果变更公告";
+            case 15:
+                return "临时公告";
+            case 16:
+                return "物资类";
+            case 17:
+                return "服务类";
+            default:
+                throw new RuntimeException(String.format("未知的类型:%d", val));
+//                return "未知的类型:"+val;
+        }
+    }
+
+    public static String getWinBidForm(int val){
+        switch (val){
+            case 1:
+                return "费率";
+            case 4:
+                return "总价";
+            default:
+                throw new RuntimeException(String.format("未知的类型:%d", val));
+//                return "未知的类型:"+val;
+        }
+    }
+}

+ 237 - 0
src/main/java/space/anyi/Application9.java

@@ -0,0 +1,237 @@
+package space.anyi;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.parser.Parser;
+import org.jsoup.select.Elements;
+
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Application9 {
+    static String indexUrl = "https://www.scgzzb.cn/webMain/noticeList.htm?page=%d&noticeType=1";
+    static String detailUrl = "https://www.scgzzb.cn/webNotice/noticeShow.htm?noticeId=%d";
+    static String fileLink = "https://www.scgzzb.cn/common/downloadFile.htm?fileId=%d&fileType=1";
+    static String baseUrl = "https://www.scgzzb.cn";
+    public static Pattern pattern = Pattern.compile("(\\d{4})(年|/|-|\\.)(\\d{1,2})(月|/|-|\\.)(\\d{1,2})");
+
+    public static void main(String[] args) throws Exception {
+        getList();
+    }
+
+    static int total = 1;
+    static int index = 1;
+    static int pageSize = 10;
+    static int count = 0;
+    public static void getList() throws Exception {
+        while (true){
+            //列表url构建
+            String listUrl = String.format(indexUrl, index);
+            System.out.println(listUrl);
+            //采集列表页
+            String res = doGet(listUrl);
+            Document document = Jsoup.parse(res);
+            Elements items = document.select("div.row.newsItem");
+            for (int i = 0; i < items.size(); i++) {
+                Element item = items.get(i);
+                String attr = item.select("h4 > span").first().attr("onclick");
+                Pattern p = Pattern.compile("noticeShow\\((\\d+)\\)");
+                Matcher m = p.matcher(attr);
+                if (m.find()) {
+                    String idStr = m.group(1);
+                    int id = Integer.parseInt(idStr);
+                    String link = String.format(detailUrl, id);
+                    String title = item.select("h4 > span").first().text().trim();
+                    System.out.println(link);
+                    System.out.println(title);
+                    //数据库是否已存在
+                    String querySql = "select DETAIL_LINK from XIN_XI_INFO_TEST where DETAIL_LINK = ?";
+                    try(Connection connection = MyDao.getConnection();
+                        PreparedStatement prepareStatement = connection.prepareStatement(querySql);){
+                        prepareStatement.setString(1,link);
+                        ResultSet resultSet = prepareStatement.executeQuery();
+                        if (resultSet.next()) {
+                            System.out.println("跳过" + link);
+                            resultSet.close();
+                            continue;
+                        }
+                        resultSet.close();
+                    }
+                    //详情
+                    String detailRes = doGet(link);
+                    Element content = Jsoup.parse(detailRes).select("div.row.newsItem01").first();
+                    String detailTitle = content.select("div.ftitle > p").first().text().trim();
+                    String dateStr = content.select("div.ftitle span").first().text().trim();
+                    Matcher matcher = pattern.matcher(dateStr);
+                    if (matcher.find()) {
+                        String month = matcher.group(3).length() == 2 ? matcher.group(3) : "0" + matcher.group(3);
+                        String day = matcher.group(5).length() == 2 ? matcher.group(5) : "0" + matcher.group(5);
+                        dateStr = matcher.group(1) + "-" + month + "-" + day;
+                    }
+                    //清洗
+                    Elements iframes = content.select("iframe#pdfViewer");
+                    for (int j = 0; j < iframes.size(); j++) {
+                        Element iframe = iframes.get(j);
+                        String href = urlClean(iframe.attr("src"), baseUrl, link);
+                        String a = String.format("<div>点击查看公告内容:<a href='%s'>%s.pdf</a></div>", href,title);
+                        iframe.remove();
+                        content.append(a);
+                    }
+                    content.select("div.media-notice-link").remove();
+                    Elements attachmentLinks = content.select("div.attachment-area a");
+                    content.select("div.attachment-area div.attachment-icon").remove();
+                    for (int j = 0; j < attachmentLinks.size(); j++) {
+                        Element attachmentLink = attachmentLinks.get(j);
+                        String onclick = attachmentLink.attr("onclick");
+                        p = Pattern.compile("downloadAttachment\\((\\d+)\\)");
+                        m = p.matcher(onclick);
+                        if (m.find()) {
+                            String fileIdStr = m.group(1);
+                            attachmentLink.attr("href", String.format(fileLink, Integer.parseInt(fileIdStr)));
+                            attachmentLink.attr("onclick","");
+                            attachmentLink.text(attachmentLink.text()+".pdf");
+                        }
+                    }
+
+                    //save
+                    //字段:ID,SOURCE_NAME(网站名称),DETAIL_LINK(详情链接),DETAIL_TITLE(详情标题),DETAIL_CONTENT(正文HTML),PAGE_TIME(列表时间),CREATE_TIME(创建时间),LIST_TITLE(列表标题),CREATE_BY(创建者名称)
+                    String SOURCE_NAME = "四川国锃招标代理有限公司";
+                    String DETAIL_LINK = link;
+                    String DETAIL_TITLE = detailTitle;
+                    String DETAIL_CONTENT = content.toString();
+                    LocalDate PAGE_TIME = LocalDate.parse(dateStr);
+                    LocalDate CREATE_TIME = LocalDate.now();
+                    String LIST_TITLE = title;
+                    String CREATE_BY = "黄略";
+
+                    String sql = "insert into " + MyDao.TABLE_NAME +"(SOURCE_NAME,DETAIL_LINK,DETAIL_TITLE,DETAIL_CONTENT,PAGE_TIME,CREATE_TIME,LIST_TITLE,CREATE_BY) VALUES (?,?,?,?,?,?,?,?)";
+                    try(Connection connection = MyDao.getConnection();
+                        PreparedStatement preparedStatement = connection.prepareStatement(sql);){
+                        preparedStatement.setString(1, SOURCE_NAME);
+                        preparedStatement.setString(2, DETAIL_LINK);
+                        preparedStatement.setString(3, DETAIL_TITLE);
+                        preparedStatement.setString(4, DETAIL_CONTENT);
+                        preparedStatement.setDate(5, Date.valueOf(PAGE_TIME));   // LocalDate -> java.sql.Date
+                        preparedStatement.setDate(6, Date.valueOf(CREATE_TIME));
+                        preparedStatement.setString(7, LIST_TITLE);
+                        preparedStatement.setString(8, CREATE_BY);
+                        preparedStatement.executeUpdate();
+                    }
+                    count++;
+                }
+            }
+            //下一页
+            Element nextPage = document.select("ul a:contains(下一页)").first();
+            if (Objects.nonNull(nextPage)) {
+                index++;
+            }else {
+                break;
+            }
+        }
+        System.out.println(count);
+    }
+
+
+    public static String doGet(String url) throws Exception {
+        String result = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet httpGet = new HttpGet(url);
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(10 * 1000).setSocketTimeout(60 * 1000)
+                .build();
+        httpGet.setConfig(requestConfig);
+        CloseableHttpResponse response = null;
+        try {
+            response = httpClient.execute(httpGet);
+            if (response.getStatusLine().getStatusCode() == 200) {
+                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
+                result = content;
+            }
+        } finally {
+            if (response != null) {
+                response.close();
+            }
+            httpClient.hashCode();
+        }
+        return result;
+    }
+
+    public static String doPost(String path) throws Exception {
+        String result = "";
+
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        // 创建http POST请求
+        HttpPost httpPost = new HttpPost(path);
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(10 * 1000).setSocketTimeout(60 * 1000)
+                .build();
+        httpPost.setConfig(requestConfig);
+        List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
+        parameters.add(new BasicNameValuePair("pagesize",pageSize+""));
+        parameters.add(new BasicNameValuePair("currentpage",index+""));
+        parameters.add(new BasicNameValuePair("search","{\"startDate\":\"\",\"endDate\":\"\",\"extVal\":\"\",\"extVal2\":\"\",\"extVal3\":\"\",\"extVal4\":\"\",\"extVal5\":\"\",\"extVal6\":-999999,\"extVal7\":-999999,\"extVal8\":null,\"extVal9\":\"02\",\"extVal10\":null,\"extVal11\":null,\"extVal12\":null,\"extVal13\":null,\"extVal14\":null,\"extVal15\":null,\"extVal16\":null,\"orderField\":\"\",\"orderType\":\"desc\",\"name\":\"\",\"code\":\"\"}"));
+
+        // 构造一个form表单式的实体
+        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
+        // 将请求实体设置到httpPost对象中
+        httpPost.setEntity(formEntity);
+        httpPost.setHeader("User-Agent",
+                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
+        CloseableHttpResponse response = null;
+        try {
+            response = httpclient.execute(httpPost);
+            if (response.getStatusLine().getStatusCode() == 200) {
+                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
+                return content;
+            }
+        } finally {
+            if (response != null) {
+                response.close();
+            }
+            httpclient.close();
+        }
+        return result;
+    }
+
+    public static String urlClean(String url,String baseUrl,String currentUrl){
+        if (url.startsWith("http")) {
+            return url;
+        }
+        String result = "";
+        if (url.startsWith("/")) {
+            //根路径开始
+            result = baseUrl + url;
+        }else if (url.startsWith("./")){
+            //当前同级目录
+            result = currentUrl.substring(0, currentUrl.lastIndexOf("/")) + url.substring(url.indexOf("./") + 1);
+        }else if (url.startsWith("../")){
+            //多级目录,取最后的uri拼接到baseUrl,等价于所有 "../" 替换成 "/"
+            result = baseUrl + url.substring(url.lastIndexOf("../") + 2);
+        }else {
+            //等价于当前目录
+            result = currentUrl.substring(0,currentUrl.lastIndexOf("/") + 1) + url;
+        }
+        return result;
+    }
+}