Java爬蟲-爬取疫苗批次信息

来源:https://www.cnblogs.com/zkool/p/18229859
-Advertisement-
Play Games

今年3月份開始,就接到通知, 根據《關於開展有關人群第二劑次脊髓灰質炎滅活疫苗補種工作的通知》國疾控衛免發〔2024〕1號文件要求,在2016年3月1日至2019年9月30日之間出生的兒童,凡無接種禁忌者,需補齊2劑次脊髓灰質炎滅活疫苗。由於我家一直是異地打針【在外漂打工,懂的都懂】,疫苗本上信息又 ...


        今年3月份開始,就接到通知, 根據《關於開展有關人群第二劑次脊髓灰質炎滅活疫苗補種工作的通知》國疾控衛免發〔2024〕1號文件要求,在2016年3月1日至2019年9月30日之間出生的兒童,凡無接種禁忌者,需補齊2劑次脊髓灰質炎滅活疫苗。由於我家一直是異地打針【在外漂打工,懂的都懂】,疫苗本上信息又特別有限【吐槽-六七年前的疫苗本缺陷太大了:無廠家,無備註是否口服,無備註是滅活還是減毒】,上周去打針被問及6年前的第一針是註射還是口服,瞬間被問住了,記得3年前幼兒園入學前的打針就已經被工作人員問過一次了,問脊髓灰質炎疫苗第二、三針是註射還是口服的,甲肝疫苗是活疫苗還是滅活疫苗。。。

 

        經過網上各種搜索,通過疫苗本上寫的批號到網上查詢追溯,最後發現在【中國食品藥品檢定研究院】https://bio.nifdc.org.cn/pqf/search.do?formAction=pqfQkcx上可以查詢,但是這個查詢也太難用了,該網站需要廠家+疫苗名+批號三個條件查詢,但我只知道批號,其它信息一概不知。。。

作為技術人員,一怒之下,寫了個爬蟲,把該網站近十年公佈的疫苗批次信息全都抓到本地。。。

上菜:

<!-- hutool工具類-->
<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-http</artifactId>
   <version>5.8.23</version>
</dependency>

<dependency>
   <groupId>org.jsoup</groupId>
   <artifactId>jsoup</artifactId>
   <version>1.17.2</version>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

 

/**
 * 獲取疫苗批次
 * @author zhaokk
 * @since 2024/5/26
 */
public class GetVaccinBatch {

    public static String BASE_URL = "https://bio.nifdc.org.cn/pqf/";

    public static void main(String[] args) throws IOException {
        String[] listUrlArray = {
                //中國食品藥品檢定研究院
                "search.do?formAction=pqfGsByJG&parameter1=1",
                //北京市藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=5b6ea8c91cf9013d011cfdfbda100041",
                //上海市食品藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d2265474b0004",
                //廣東省藥品檢驗所
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d226a9159001c",
                //四川省藥品檢驗研究院(四川省醫療器械檢測中心)
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d226ba310001e",
                //湖北省藥品監督檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d22697942001a",
                //吉林省藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d226392100002",
                //甘肅省藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=4028813a1d225be5011d226c637d0020",
                //重慶市食品藥品檢驗檢測研究院
                "search.do?formAction=pqfGsByJG&parameter1=20190917c001",
                //山東省食品藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=20190924c001",
                //遼寧省藥品檢驗檢測院
                "search.do?formAction=pqfGsByJG&parameter1=20210315c001",
                //雲南省食品藥品監督檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=20210926c001",
                //河北省藥品醫療器械檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=20211011c001",
                //浙江省食品藥品檢驗研究院
                "search.do?formAction=pqfGsByJG&parameter1=20210210c002"
        };

        MongoDbUtils.connect("mongodb://127.0.0.1:27017", "vaccin-batch");
        for (String listUrl : listUrlArray) {
            //發送http請求
            Document document = Jsoup.connect(BASE_URL+listUrl).get();
            Elements aList = document.select("table tr td > a");

            for (int i = aList.size()-1; i >= 0; i--) {
                Element a = aList.get(i);
                String atext = a.text();
                String ahref = a.attr("href");
                String publishDateStr = atext.substring(atext.length()-11, atext.length()-1);
                System.out.println(atext + ":" + ahref);
                System.out.println("公佈日期:" + publishDateStr);

                org.bson.Document saveLogDoc = new org.bson.Document();
                saveLogDoc.append("notice_list_url", BASE_URL+listUrl);
                saveLogDoc.append("notice_detail_url", BASE_URL+ahref);
                saveLogDoc.append("notice_title", atext);
                List<org.bson.Document> saveLogList = MongoDbUtils.findBy("vaccin-batch-savelog", saveLogDoc);
                if(!saveLogList.isEmpty()){
                    System.out.println(BASE_URL+ahref + "【"+ atext + "】已存在,跳過");
                    continue;
                }

                viewDetail(BASE_URL+ahref, atext);
                saveLogDoc.append("publish_date", publishDateStr);
                saveLogDoc.append("create_time", DateUtil.now());
                MongoDbUtils.insert("vaccin-batch-savelog", saveLogDoc);

            }
        }

    }

    public static void viewDetail(String noticeDetailUrl, String noticeTitle) throws IOException {
//        Document document = Jsoup.connect(noticeDetailUrl).get();
        Connection.Response resp = Jsoup.connect(noticeDetailUrl)
                .timeout(60000)
                .method(Connection.Method.GET)
                .maxBodySize(0)
                .followRedirects(false)
                .execute();
        String htmlStr = new String(resp.bodyAsBytes());

        Document document = Jsoup.parse(htmlStr);
        Elements theadList = document.select("table thead tr");
        if(theadList.isEmpty() || theadList.size() != 2){
            throw new RuntimeException("未解析到信息");
        }
        Elements theadCols = theadList.get(1).select("td");

        Elements tbodyList = document.select("table thead + tbody tr");
        if(tbodyList.isEmpty()){
            throw new RuntimeException("未解析到信息");
        }
        for (Element row : tbodyList) {
            Elements cols = row.select("td");
            if(cols.size() != theadCols.size()){
//                break;
                System.out.println(document);
                System.out.println(noticeDetailUrl);
                System.out.println(row);
                throw new RuntimeException("未解析到正確的信息");
            }

            org.bson.Document mongoDoc = new org.bson.Document();
            for (int i = 0; i < cols.size(); i++) {
                String key = FieldEnum.getName(theadCols.get(i).text());
                if(StrUtil.isBlank(key)){
                    continue;
                }
                mongoDoc.append(key, cols.get(i).text());
            }
            mongoDoc.append("notice_title", noticeTitle);
            mongoDoc.append("notice_detail_url", noticeDetailUrl);
            //保存資料庫
            MongoDbUtils.insert("vaccin-batch", mongoDoc);
        }
    }

}


/**
 * @author zhaokk
 * @since 2024/5/26
 */
public enum FieldEnum {

    PRODUCT_NAME("產品名稱", "product_name"),
    SPEC("規格", "spec"),
    BATCH_NO("批號", "batch_no"),
    QUANTITY("簽發量", "quantity"),
    VALID_DATE("有效期至", "valid_date"),
    PRODUCER("生產企業", "producer"),
    PRODUCER_ORG("上市許可持有人", "producer"),
    CHECK_NO("收檢編號", "check_no"),
    CERT_NO("證書編號", "cert_no"),
    REPORT_NO("報告編號", "report_no"),
    SIGN_DATE("簽發日期", "sign_date"),
    SIGN_REMARK("簽髮結論", "sign_remark"),
    SIGN_ORG("批簽發機構", "sign_org")
    ;

    private String remark;
    private String name;

    FieldEnum(String remark, String name) {
        this.remark = remark;
        this.name = name;
    }

    public static String getName(String remark){
        for(FieldEnum value : FieldEnum.values()){
            if(remark.equals(value.getRemark())){
                return value.getName();
            }
        }
        return null;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

再搭配一道菜mogodb Util,不用跑什麼tomcat,運行main函數直接就是開乾,最後通過Navicat等工具連上隨意檢索。

 

import com.mongodb.BasicDBObject;
import com.mongodb.MongoWriteException;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import java.util.ArrayList;
import java.util.List;

/**
 * MongoDb 操作類
 * @author zhaokui
 * 2018年1月31日 
 */
public class MongoDbUtils {
   
   private static MongoDatabase db;
    /** 
     * 鏈接資料庫 
     *            
     * @param uri
     *            主機名 + 埠號
     * @param databaseName 
     *            資料庫名稱 
     *            
     */
    public static void connect(String uri, String databaseName) {
        MongoClient client = MongoClients.create(uri);
        db = client.getDatabase(databaseName);  
    } 
    
    public static MongoCollection<Document> getCollection(String collectionName){
       return db.getCollection(collectionName);
    }
    
    
    /** 
     * 插入一個文檔 
     *  
     * @param document 
     *            文檔 
     */  
    public static void insert(String collectionName, Document document) {  
       getCollection(collectionName).insertOne(document);  
    }
    /** 
     * 插入一個文檔 
     *  
     * @param document 
     *            文檔 
     */  
    public static void insertv2(String collectionName, Document document) throws Exception {  
          try{
             getCollection(collectionName).insertOne(document);
          }catch(MongoWriteException e) {
             e.printStackTrace();
          }
    }  
    
    /**
     * 查找對象 - 根據主鍵_id
     * 
     * @param collectionName
     * @param id
     * @return
     */
    public static Document findById(String collectionName, String id) {
        ObjectId _idobj = null;
        try {
            _idobj = new ObjectId(id);
        } catch (Exception e) {
            return null;
        }
        Document myDoc = getCollection(collectionName).find(Filters.eq("_id", _idobj)).first();
        return myDoc;
    }
  
    /** 
     * 查詢所有文檔 
     *  
     * @return 所有文檔集合 
     */  
    public static List<Document> findAll(String collectionName) {  
        List<Document> results = new ArrayList<Document>();  
        FindIterable<Document> iterables = getCollection(collectionName).find();  
        MongoCursor<Document> cursor = iterables.iterator();  
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        }  
  
        return results;  
    }  
  
    /** 
     * 查詢所有文檔 
     *  
     * @return 所有文檔集合 
     */  
    public static List<Document> findAll(String collectionName, Bson orderBy) {  
        List<Document> results = new ArrayList<Document>();  
        FindIterable<Document> iterables = getCollection(collectionName).find().sort(orderBy);  
        MongoCursor<Document> cursor = iterables.iterator();  
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        }  
  
        return results;  
    } 
    
    /** 
     * 根據條件查詢 
     *  
     * @param filter 
     *            查詢條件 //註意Bson的幾個實現類,BasicDBObject, BsonDocument, 
     *            BsonDocumentWrapper, CommandResult, Document, RawBsonDocument 
     * @return 返回集合列表 
     */  
    public static List<Document> findBy(String collectionName, Bson filter) {  
        List<Document> results = new ArrayList<Document>();  
        FindIterable<Document> iterables = getCollection(collectionName).find(filter);
        MongoCursor<Document> cursor = iterables.iterator();  
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        }  
  
        return results;  
    }  
    
    /** 
     * 根據條件查詢 + 排序
     *  
     * @param filter 
     *            查詢條件 //註意Bson的幾個實現類,BasicDBObject, BsonDocument, 
     *            BsonDocumentWrapper, CommandResult, Document, RawBsonDocument 
     * @return 返回集合列表 
     */  
    public static List<Document> findBy(String collectionName, Bson filter, Bson orderBy) {  
        List<Document> results = new ArrayList<Document>();  
        FindIterable<Document> iterables = getCollection(collectionName).find(filter).sort(orderBy);  
        MongoCursor<Document> cursor = iterables.iterator();  
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        }  
  
        return results;  
    }  
    
    public static List<Document> findBy(String collectionName, Bson filter, Bson orderBy, int pageSize) {  
        List<Document> results = new ArrayList<Document>();  
        FindIterable<Document> iterables = getCollection(collectionName).find(filter).sort(orderBy).limit(pageSize);  
        MongoCursor<Document> cursor = iterables.iterator();  
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        }  
        return results;  
    }  
    
    /** 統計數 */
    public static long getCount(String collectionName, Bson filter) {
        return getCollection(collectionName).countDocuments(filter);
    }
    
    /** 分頁查詢 */
    public static List<Document> findByPage(String collectionName, Bson filter, int pageNo, int pageSize) {
       List<Document> results = new ArrayList<Document>();  
        Bson orderBy = new BasicDBObject("_id", -1);
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).sort(orderBy).skip((pageNo - 1) * pageSize).limit(pageSize).iterator();
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        } 
        return results;  
    }
    
    /** 分頁查詢+排序 */
    public static List<Document> findByPage(String collectionName, Bson filter, Bson orderBy, int pageNo, int pageSize) {
       List<Document> results = new ArrayList<Document>();  
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).sort(orderBy).skip((pageNo - 1) * pageSize).limit(pageSize).iterator();
        while (cursor.hasNext()) {  
            results.add(cursor.next());  
        } 
        return results;  
    }
  
    /** 
     * 更新查詢到的第一個 
     *  
     * @param filter 
     *            查詢條件 
     * @param update 
     *            更新文檔 
     * @return 更新結果 
     */  
    public static UpdateResult updateOne(String collectionName, Bson filter, Bson update) {  
        UpdateResult result = getCollection(collectionName).updateOne(filter, update);  
  
        return result;  
    }  
  
    /** 
     * 更新查詢到的所有的文檔 
     *  
     * @param filter 
     *            查詢條件 
     * @param update 
     *            更新文檔 
     * @return 更新結果 
     */  
    public static UpdateResult updateMany(String collectionName, Bson filter, Bson update) {  
        UpdateResult result = getCollection(collectionName).updateMany(filter, update);  
  
        return result;  
    }  
    
    /**
     * FIXME
     * 
     * @param collectionName
     * @param id
     * @param newdoc
     * @return
     */
    public static Document updateById(String collectionName, String id, Document newdoc) {
        ObjectId _idobj = null;
        try {
            _idobj = new ObjectId(id);
        } catch (Exception e) {
            return null;
        }
        Bson filter = Filters.eq("_id", _idobj);
        // coll.replaceOne(filter, newdoc); // 完全替代
        getCollection(collectionName).updateOne(filter, new Document("$set", newdoc));
        return newdoc;
    }
  
    /** 
     * 更新一個文檔, 結果是replacement是新文檔,老文檔完全被替換 
     *  
     * @param filter 
     *            查詢條件 
     * @param replacement 
     *            跟新文檔 
     */  
    public static void replace(String collectionName, Bson filter, Document replacement) {  
        getCollection(collectionName).replaceOne(filter, replacement);  
    }  
  
    /** 
     * 根據條件刪除一個文檔 
     *  
     * @param filter 
     *            查詢條件 
     */  
    public static void deleteOne(String collectionName, Bson filter) {  
        getCollection(collectionName).deleteOne(filter);  
    }  
  
    /** 
     * 根據條件刪除多個文檔 
     *  
     * @param filter 
     *            查詢條件 
     */  
    public static void deleteMany(String collectionName, Bson filter) {  
        getCollection(collectionName).deleteMany(filter);  
    } 
      
    /**
     * 通過ID刪除
     * 
     * @param collectionName
     * @param id
     * @return
     */
    public static long deleteById(String collectionName, String id) {
       long count = 0;
        ObjectId _id = null;
        try {
            _id = new ObjectId(id);
        } catch (Exception e) {
            return 0;
        }
        Bson filter = Filters.eq("_id", _id);
        DeleteResult deleteResult = getCollection(collectionName).deleteOne(filter);
        count = deleteResult.getDeletedCount();
        return count;
    }
       
}

 

翻譯

搜索

複製


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 為什麼會突然想到寫這麼一個大雜燴的博文呢,必須要從筆者幾年前的一次面試說起。當時的我年輕氣盛,在簡歷上放了自己的博客地址,而面試官應該是翻了我的博客,好幾道面試題都是圍繞著我的博文來提問。其中一個問題,直接使得空氣靜止了五分鐘,也是自從那次面試,我告訴自己,工作實戰中總結的經驗,一定要知其然知其所以... ...
  • 目錄前端平臺搭建(Vue2.6,App:HBulderX)創建Vue2.6項目下載相應插件方便開發路由配置對連接後端進行一些配置(main.js文件)導入ElementUI組件組件 | Element同步與非同步axios非同步請求框架 前端平臺搭建(Vue2.6,App:HBulderX) 創建Vue ...
  • 一、場景復現 一個經典的面試題 0.1 + 0.2 0.3 // false 為什麼是false呢? 先看下麵這個比喻 比如一個數 1÷3=0.33333333...... 3會一直無限迴圈,數學可以表示,但是電腦要存儲,方便下次取出來再使用,但0.333333...... 這個數無限迴圈,再大的 ...
  • title: 深入理解Vue 3:計算屬性與偵聽器的藝術 date: 2024/5/30 下午3:53:47 updated: 2024/5/30 下午3:53:47 categories: 前端開發 tags: Vue3 計算屬性 偵聽器 路由 模板 性能優化 實戰案例 前言 Vue 3的新特性簡 ...
  • 效果預覽 視頻畫面 網路請求 代碼實現 ZLMRTCClient.js 當前使用的版本: 1.0.1 Mon Mar 27 2023 19:11:59 GMT+0800 首先需要修改 ZLMRTCClient.js 的代碼,解決由於網路導致播放失敗時無法觸發 WEBRTC_OFFER_ANWSER_ ...
  • UML類圖 類圖定義規則 屬性和方法前加上(+、-、#、留空)分別代表:公開(public)、私有(private)、保護(protected)、預設(default) 方法括弧內為參數類型,冒號後為返回值類型 下劃線表示 靜態(static),斜體表示 抽象(abstract) 類圖關係表示法 其 ...
  • 什麼是心跳包(心跳機制) 先看一下wiki上的說法: 心跳包(英語:Heartbeat)在電腦科學中指一種周期性的信號,通過硬體或軟體的形式來檢測行為的正常與否,或者與電腦系統是否一致。[1] 通常,機器間會每隔幾秒鐘發送一次心跳包。 如果接收終端沒有在指定時間內(通常是幾個心跳包發送的時間間隔 ...
  • 前言 觀察者模式(Observer Pattern)是一種行為型設計模式,它定義了一種一對多的依賴關係,當一個對象的狀態發生改變時,其所有依賴者都會收到通知並自動更新。 在觀察者模式中,有兩種主要的角色: 觀察者(Observer):觀察者是一個介面或抽象類,它定義了一個更新的介面,使得被觀察者在狀 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...