|
|
@@ -0,0 +1,267 @@
|
|
|
+package space.anyi;
|
|
|
+
|
|
|
+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.select.Elements;
|
|
|
+import us.codecraft.webmagic.Page;
|
|
|
+import us.codecraft.webmagic.Request;
|
|
|
+import us.codecraft.webmagic.Site;
|
|
|
+import us.codecraft.webmagic.Spider;
|
|
|
+import us.codecraft.webmagic.model.HttpRequestBody;
|
|
|
+import us.codecraft.webmagic.processor.PageProcessor;
|
|
|
+import us.codecraft.webmagic.utils.HttpConstant;
|
|
|
+
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.sql.*;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+public class Application12 implements PageProcessor {
|
|
|
+
|
|
|
+ //初始url
|
|
|
+ static String indexUrl = "https://ggzy.hainan.gov.cn/inteligentsearch/rest/esinteligentsearch/getFullTextDataNew";
|
|
|
+ static String baseUrl = "https://ggzy.hainan.gov.cn";
|
|
|
+ static int total = 0;
|
|
|
+ static int index = 0;
|
|
|
+ static int pageSize = 10;
|
|
|
+ public static Pattern pattern = Pattern.compile("(\\d{4})(年|/|-|\\.)(\\d{1,2})(月|/|-|\\.)(\\d{1,2})");
|
|
|
+
|
|
|
+ //配置
|
|
|
+ private Site site = new Site().setCharset(StandardCharsets.UTF_8.name())
|
|
|
+ .setTimeOut(100 * 1000) //超时时间
|
|
|
+ .setRetryTimes(3) //重试请求次数
|
|
|
+ .setRetrySleepTime(3000) //重试间隔时间 请求头
|
|
|
+ .setUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36");
|
|
|
+ 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 + result.substring(result.lastIndexOf("../") + 2);
|
|
|
+ }else {
|
|
|
+ //等价于当前目录
|
|
|
+ result = currentUrl.substring(0,currentUrl.lastIndexOf("/") + 1) + url;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void process(Page page) {
|
|
|
+ String currentUrl = page.getUrl().toString();
|
|
|
+ if (currentUrl.equals(indexUrl)) {
|
|
|
+ String res = page.getRawText();
|
|
|
+ JSONObject result = new JSONObject(res).getJSONObject("result");
|
|
|
+ total = result.getInt("totalcount");
|
|
|
+ JSONArray items = result.getJSONArray("records");
|
|
|
+ for (int i = 0; i < items.length(); i++) {
|
|
|
+ JSONObject item = items.getJSONObject(i);
|
|
|
+ String title = item.get("title").toString();
|
|
|
+ String href = item.get("linkurl").toString();
|
|
|
+ String dateStr = item.get("infodate").toString();
|
|
|
+ String link = urlClean(href,baseUrl,currentUrl);
|
|
|
+ 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();
|
|
|
+ } catch (SQLException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ //详情请求
|
|
|
+ Request detailRequest = new Request(link);
|
|
|
+ detailRequest.putExtra("title",title);
|
|
|
+ detailRequest.putExtra("listDate",LocalDate.parse(dateStr));
|
|
|
+ page.addTargetRequest(detailRequest);
|
|
|
+ }
|
|
|
+ //下一页
|
|
|
+ if (index<=total) {
|
|
|
+ index+=pageSize;
|
|
|
+ String endTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
|
|
+ String jsonStr = "{\n" +
|
|
|
+ " \"token\": \"\",\n" +
|
|
|
+ " \"pn\": "+index+",\n" +
|
|
|
+ " \"rn\": "+pageSize+",\n" +
|
|
|
+ " \"sdt\": \"\",\n" +
|
|
|
+ " \"edt\": \"\",\n" +
|
|
|
+ " \"wd\": \" \",\n" +
|
|
|
+ " \"inc_wd\": \"\",\n" +
|
|
|
+ " \"exc_wd\": \"\",\n" +
|
|
|
+ " \"fields\": \"title\",\n" +
|
|
|
+ " \"cnum\": \"001\",\n" +
|
|
|
+ " \"sort\": \"{\\\"istop\\\":\\\"0\\\",\\\"ordernum\\\":\\\"0\\\",\\\"webdate\\\":\\\"0\\\"}\",\n" +
|
|
|
+ " \"ssort\": \"title\",\n" +
|
|
|
+ " \"cl\": 200,\n" +
|
|
|
+ " \"terminal\": \"\",\n" +
|
|
|
+ " \"condition\": [\n" +
|
|
|
+ " {\n" +
|
|
|
+ " \"fieldName\": \"categorynum\",\n" +
|
|
|
+ " \"equal\": \"003001001\",\n" +
|
|
|
+ " \"notEqual\": null,\n" +
|
|
|
+ " \"equalList\": null,\n" +
|
|
|
+ " \"notEqualList\": null,\n" +
|
|
|
+ " \"isLike\": true,\n" +
|
|
|
+ " \"likeType\": 2\n" +
|
|
|
+ " }\n" +
|
|
|
+ " ],\n" +
|
|
|
+ " \"time\": [\n" +
|
|
|
+ " {\n" +
|
|
|
+ " \"fieldName\": \"webdate\",\n" +
|
|
|
+ " \"startTime\": \"1970-01-01 00:00:00\",\n" +
|
|
|
+ " \"endTime\": \""+endTime+"\"\n" +
|
|
|
+ " }\n" +
|
|
|
+ " ],\n" +
|
|
|
+ " \"highlights\": \"title\",\n" +
|
|
|
+ " \"statistics\": null,\n" +
|
|
|
+ " \"unionCondition\": null,\n" +
|
|
|
+ " \"accuracy\": \"\",\n" +
|
|
|
+ " \"noParticiple\": \"1\",\n" +
|
|
|
+ " \"searchRange\": [],\n" +
|
|
|
+ " \"isBusiness\": \"1\"\n" +
|
|
|
+ "}";
|
|
|
+ HttpRequestBody requestBody = HttpRequestBody.json(jsonStr,StandardCharsets.UTF_8.name());
|
|
|
+ Request request = new Request(indexUrl).setMethod(HttpConstant.Method.POST);
|
|
|
+ request.addHeader("content-type","application/json;");
|
|
|
+ request.setRequestBody(requestBody);
|
|
|
+ page.addTargetRequest(request);
|
|
|
+ }
|
|
|
+ page.setSkip(true);
|
|
|
+ } else {
|
|
|
+ //处理详情网址
|
|
|
+ String detailRes = page.getRawText();
|
|
|
+ Document detailDocument = Jsoup.parse(detailRes);
|
|
|
+ Element content = detailDocument.select("div.article-info.jyxx-info").first();
|
|
|
+ String detailTitle = detailDocument.select("h3.infotitle").first().text().trim();
|
|
|
+ //清洗
|
|
|
+ Elements imgs = content.select("img");
|
|
|
+ for (int j = 0; j < imgs.size(); j++) {
|
|
|
+ Element img = imgs.get(j);
|
|
|
+ img.attr("src",urlClean(img.attr("src"),baseUrl,currentUrl));
|
|
|
+ }
|
|
|
+ Elements as = content.select("a");
|
|
|
+ for (int j = 0; j < as.size(); j++) {
|
|
|
+ Element a = as.get(j);
|
|
|
+ String onclick = a.attr("onclick");
|
|
|
+ Pattern p = Pattern.compile("ztbfjyz\\('([^']+)'");
|
|
|
+ Matcher m = p.matcher(onclick);
|
|
|
+ if (m.find()) {
|
|
|
+ String url = m.group(1);
|
|
|
+ a.attr("href",urlClean(url,baseUrl,currentUrl));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ content.select("div.hidden").remove();
|
|
|
+
|
|
|
+ //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 = currentUrl;
|
|
|
+ String DETAIL_TITLE = detailTitle;
|
|
|
+ String DETAIL_CONTENT = content.toString();
|
|
|
+ LocalDate PAGE_TIME = ((LocalDate) page.getRequest().getExtra("listDate"));
|
|
|
+ LocalDate CREATE_TIME = LocalDate.now();
|
|
|
+ String LIST_TITLE = ((String) page.getRequest().getExtra("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();
|
|
|
+ } catch (SQLException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Site getSite() {
|
|
|
+ return site;
|
|
|
+ }
|
|
|
+
|
|
|
+ //启动
|
|
|
+ public static void main(String[] args) {
|
|
|
+ String endTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
|
|
+ String jsonStr = "{\n" +
|
|
|
+ " \"token\": \"\",\n" +
|
|
|
+ " \"pn\": "+index+",\n" +
|
|
|
+ " \"rn\": "+pageSize+",\n" +
|
|
|
+ " \"sdt\": \"\",\n" +
|
|
|
+ " \"edt\": \"\",\n" +
|
|
|
+ " \"wd\": \" \",\n" +
|
|
|
+ " \"inc_wd\": \"\",\n" +
|
|
|
+ " \"exc_wd\": \"\",\n" +
|
|
|
+ " \"fields\": \"title\",\n" +
|
|
|
+ " \"cnum\": \"001\",\n" +
|
|
|
+ " \"sort\": \"{\\\"istop\\\":\\\"0\\\",\\\"ordernum\\\":\\\"0\\\",\\\"webdate\\\":\\\"0\\\"}\",\n" +
|
|
|
+ " \"ssort\": \"title\",\n" +
|
|
|
+ " \"cl\": 200,\n" +
|
|
|
+ " \"terminal\": \"\",\n" +
|
|
|
+ " \"condition\": [\n" +
|
|
|
+ " {\n" +
|
|
|
+ " \"fieldName\": \"categorynum\",\n" +
|
|
|
+ " \"equal\": \"003001001\",\n" +
|
|
|
+ " \"notEqual\": null,\n" +
|
|
|
+ " \"equalList\": null,\n" +
|
|
|
+ " \"notEqualList\": null,\n" +
|
|
|
+ " \"isLike\": true,\n" +
|
|
|
+ " \"likeType\": 2\n" +
|
|
|
+ " }\n" +
|
|
|
+ " ],\n" +
|
|
|
+ " \"time\": [\n" +
|
|
|
+ " {\n" +
|
|
|
+ " \"fieldName\": \"webdate\",\n" +
|
|
|
+ " \"startTime\": \"1970-01-01 00:00:00\",\n" +
|
|
|
+ " \"endTime\": \""+endTime+"\"\n" +
|
|
|
+ " }\n" +
|
|
|
+ " ],\n" +
|
|
|
+ " \"highlights\": \"title\",\n" +
|
|
|
+ " \"statistics\": null,\n" +
|
|
|
+ " \"unionCondition\": null,\n" +
|
|
|
+ " \"accuracy\": \"\",\n" +
|
|
|
+ " \"noParticiple\": \"1\",\n" +
|
|
|
+ " \"searchRange\": [],\n" +
|
|
|
+ " \"isBusiness\": \"1\"\n" +
|
|
|
+ "}";
|
|
|
+ HttpRequestBody requestBody = HttpRequestBody.json(jsonStr,StandardCharsets.UTF_8.name());
|
|
|
+ Request request = new Request(indexUrl).setMethod(HttpConstant.Method.POST);
|
|
|
+ request.addHeader("content-type","application/json;");
|
|
|
+ request.setRequestBody(requestBody);
|
|
|
+ Spider spider = Spider.create(new Application12())
|
|
|
+ .addRequest(request);
|
|
|
+ System.out.println("start");
|
|
|
+ spider.run();
|
|
|
+ System.out.println("end");
|
|
|
+ }
|
|
|
+}
|