今年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;
} }

翻译

搜索

复制

Java爬虫-爬取疫苗批次信息的更多相关文章

  1. Java爬虫爬取京东商品信息

    以下内容转载于<https://www.cnblogs.com/zhuangbiing/p/9194994.html>,在此仅供学习借鉴只用. Maven地址 <dependency ...

  2. 简单的python爬虫--爬取Taobao淘女郎信息

    最近在学Python的爬虫,顺便就练习了一下爬取淘宝上的淘女郎信息:手法简单,由于淘宝网站本上做了很多的防爬措施,应此效果不太好! 爬虫的入口:https://mm.taobao.com/json/r ...

  3. Python爬虫-爬取京东商品信息-按给定关键词

    目的:按给定关键词爬取京东商品信息,并保存至mongodb. 字段:title.url.store.store_url.item_id.price.comments_count.comments 工具 ...

  4. 一个简单java爬虫爬取网页中邮箱并保存

    此代码为一十分简单网络爬虫,仅供娱乐之用. java代码如下: package tool; import java.io.BufferedReader; import java.io.File; im ...

  5. node.js爬虫爬取拉勾网职位信息

    简介 用node.js写了一个简单的小爬虫,用来爬取拉勾网上的招聘信息,共爬取了北京.上海.广州.深圳.杭州.西安.成都7个城市的数据,分别以前端.PHP.java.c++.python.Androi ...

  6. java爬虫爬取网页内容前,对网页内容的编码格式进行判断的方式

    近日在做爬虫功能,爬取网页内容,然后对内容进行语义分析,最后对网页打标签,从而判断访问该网页的用户的属性. 在爬取内容时,遇到乱码问题.故需对网页内容编码格式做判断,方式大体分为三种:一.从heade ...

  7. Java爬虫爬取网站电影下载链接

    之前有看过一段时间爬虫,了解了爬虫的原理,以及一些实现的方法,本项目完成于半年前,一直放在那里,现在和大家分享出来. 网络爬虫简单的原理就是把程序想象成为一个小虫子,一旦进去了一个大门,这个小虫子就像 ...

  8. java爬虫爬取的html内容中空格(&nbsp;)变为问号“?”的解决方法

    用java编写的爬虫,使用xpath爬取内容后,发现网页源码中的 全部显示为?(问号),但是使用字符串的replace("?", ""),并不能替换,网上找了一 ...

  9. python爬虫爬取汽车页面信息,并附带分析(静态爬虫)

    环境: windows,python3.4 参考链接: https://blog.csdn.net/weixin_36604953/article/details/78156605 代码:(亲测可以运 ...

  10. java爬虫爬取资源,小白必须会的入门代码块

    java作为目前最火的语言之一,他的实用性也在被无数的java语言爱好者逐渐的开发,目前比较流行的爬取资源,用java来做也更简单一些,下面是爬取网页上所有手机型号,参数等极为简便的数据 packag ...

随机推荐

  1. Triton部署mmdeploy导出的TensorRT模型失败篇

    记录一下历程,最终没有部署成功,应该是Ubantu系统版本的问题.现在没有时间搞了,先记录一下,后续用到再填坑. Triton demo git clone -b r22.06 https://git ...

  2. (节流)js防止重复频繁点击或者点击过快方法

    1.方法一:用定时器定时,没跑完定时器,点击按钮无效 <script> var isClick = true; $("button").on("click&q ...

  3. Java实现学生投票系统

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 代码 im ...

  4. 02_Vue模板语法

    Vue模板语法有2大类:         1.插值语法:           功能:用于解析标签体内容.           写法:{{xxx}},xxx是js的表达式,且可以直接读取到data中的所 ...

  5. 基于EasyCV复现ViTDet:单层特征超越FPN

    简介: ViTDet其实是恺明团队MAE和ViT-based Mask R-CNN两个工作的延续.MAE提出了ViT的无监督训练方法,而ViT-based Mask R-CNN给出了用ViT作为bac ...

  6. 应用容灾中,MySQL数据表是否需要跨云同步?

    简介: 容灾系统的重要目标在于保证系统数据和服务的"连续性".当系统发生故障时,容灾系统能够快速恢复服务和保证数据的有效性.为了防止天灾人祸.不可抗力,在同城或异地建立对应的IT系 ...

  7. 【视频特辑】提效神器!如何用Quick BI高效配置员工的用数权限

    ​简介:随着企业数字化进程逐步加速,企业所产生和积累的数据资源日益增多.每当员工的用数权限发生变动,管理员都需要进行复杂繁琐的重复性配置流程,不仅耗时耗力还容易出错. 如何能便捷地对员工用数权限进行高 ...

  8. 阿里云混合云Apsara Stack 2.0发布 加速政企数智创新

    ​简介: 2021年10月21日,杭州 – 今日,阿里云于云栖大会正式发布Apsara Stack 2.0,从面向单一私有云场景,升级为服务大型集团云&行业云场景.新一代Apsara Stac ...

  9. SpringMVC学习五(resultful风格/异常处理/注解)

    resultful风格 异常处理 1.Restfule风格 Restfule风格是一种软件架构风格,而不是标准,只是提供了一种设计原则和约束条件.主要适用于客户端和服务器端交互的软件.是基于http协 ...

  10. 简说Python之列表,元祖,字典

    目录 Python列表 创建列表 添加元素 查询元素 列表分片 分片简写 修改元素 一些其他添加列表元素的方法 extend() insert() 删除元素 remove()删除 del 通过索引删除 ...