目錄
前言
轉眼已經到了2月份了,武漢的新型冠狀病毒事件幾乎席捲了咱們整個中國,甚至還傳到了海外,可謂是全民都在爲此事件做自己力所能及的事情,其中就包括咱們程序員,就有大佬們自發的組織起了爲武漢在github上做了一個開源項目武漢防疫信息收集平臺,具體細節內容這裏就不贅述了,詳情可以戳鏈接看我之前的一篇文章:《衆志成城抗肺炎,程序猿也發揮大作用》
今天之後我也爲此做點小小的貢獻吧,作爲一名程序員,這裏就寫一點爬取的教程吧,希望能夠幫助到大家,以及其他程序員,可以快速的開發和集成其他的功能,比如將所有的信息整合,做成另外的一個信息展示平臺 網站或者小程序等等。期待你們的作品,如果有我需要的小小的一份幫助的話,可以在文章底部留言或者私信我,我一定會盡快回復貢獻自己的一份綿薄之力。
一、要爬取的內容
今天也是看了公衆號阿里技術的文章:12小時上線“新冠肺炎同程查詢工具”,開發者這樣狙擊疫情
瞭解到已經有大佬們整理和製作了同行程的查詢網站,能夠幫助到更多人解決問題,這裏感謝一下這些無私奉獻的大佬們。我這裏的爬取並沒有惡意的意思,正如我提到的,我是希望能夠將多個平臺的功能整理出API,然後能夠讓更多人整合這麼多個平臺的功能,然後再次整合成網站甚至製作成小程序,雖然我也會做小程序。
爬取的地址:http://2019ncov.nosugartech.com/search.html 或者 http://2019ncov.nosugartech.com
二、抓包數據
抓包可以利用抓包工具或者直接瀏覽器F12看請求數據 ,這裏我就直接省略跳過去了,想了解的可以自己搜索教程,我用的抓包工具是fiddler。
請求地址:http://2019ncov.nosugartech.com/search.html
1、分析
這裏發現當我請求這個頁面的抓包數據如圖所示,我們可以清楚的看到請求的url有這些,我們可以猜測到這個網站的前端是用了Layui框架,然後所有的數據在一個data.json裏面,然後我試着輸入日期和車次搜索了一下,發現沒有新的請求,所以可以猜測到數據應該沒有和數據庫交互,數據都是放在data.json文件裏面,然後頁面的展示表格和搜索展示是用了layui的表格組件,這樣可以保證搜索的人即使再多,也不會出現崩潰,關於網站的架構模式這篇文章不是重點,我也就不繼續分析和猜測了。
這樣也降低了我們的爬取難度,我們只要直接請求這個http://2019ncov.nosugartech.com/data.json?439072文件就可以拿到所有的數據了,然後不管你是每次都請求這個data.json,還是將數據入庫或redis緩存裏,然後每隔一定時間請求一次data.json都可以,看你想怎麼弄。(這次感謝這些大佬們默默的整理這些數據,整理數據是繁瑣的,但也是重中之重)
很多人會問這個問號後面的439072是什麼東東,我們直接查看源代碼,可以看到這個只是一個防止瀏覽器有緩存的一個版本號,
2、代碼demo
/**
* 新型冠狀病毒肺炎確診患者同行程查詢工具
* @return
*/
public static String getSameTripData(){
String url="http://2019ncov.nosugartech.com/data.json?"+Math.floor(new Date().getTime()/1000/3600);
//模擬請求
HttpPojo httpPojo = new HttpPojo();
httpPojo.setHttpHost("2019ncov.nosugartech.com");
httpPojo.setHttpAccept("application/json, text/javascript, */*; q=0.01");
httpPojo.setHttpConnection("keep-alive");
httpPojo.setHttpUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
httpPojo.setHttpReferer("http://2019ncov.nosugartech.com/search.html");
httpPojo.setHttpOrigin("http://2019ncov.nosugartech.com/search.html");
Map paramObj = new HashMap();
String htmlResult = httpSendGet(url, paramObj, httpPojo); //整個html頁面
System.out.println(htmlResult);
//遍歷入庫或者存redis等操作
/*JSONObject dataJo = JSONObject.parseObject(htmlResult);
String data = dataJo.getString("data");//拿到所有數據
JSONArray array = JSONArray.parseArray(data);
for (int i = 0; i < array.size(); i++) {
JSONObject tripJo = JSONObject.parseObject(array.getString(i));
String t_no = tripJo.getString("t_no");
System.out.println("t_no:"+t_no);
//入庫操作
}*/
return htmlResult;
}
運行效果:可以自行復制打印出來的結果在 在線json格式化網站解析一下看看:http://www.bejson.com/count.html
數據就不複製出來了,因爲數據實在是太多,csdn博客會提示字數太多,發佈不了,所以大家自己運行獲取結果哈
3、各個字段的含義
{
"id": 946,
"t_date": "2020-01-28",
"t_start": "2020/01/28 13:30:00",
"t_end": "2020/01/28 23:59:59",
"t_type": 5,
"t_no": "淮北市1路公交車",
"t_memo": "1月31日確診",
"t_no_sub": "",
"t_pos_start": "淮北淮海路",
"t_pos_end": "淮北市人民醫院",
"source": "http://wjw.huaibei.gov.cn/xxfb/tzgg/55971291.html",
"who": "淮北市衛生健康委員會",
"verified": 1,
"created_at": "2020/02/02 21:19:11",
"updated_at": "2020/02/02 21:35:21"
}, {
"id": 855,
"t_date": "2020-01-27",
"t_start": "2020/01/27 00:00:00",
"t_end": "2020/01/27 23:59:59",
"t_type": 1,
"t_no": "JD5859",
"t_memo": "",
"t_no_sub": "",
"t_pos_start": "北京",
"t_pos_end": "南昌",
"source": "https://mp.weixin.qq.com/s/HYcnAc-G5GpgEGFJSPsZBg",
"who": "人民日報",
"verified": 1,
"created_at": "2020/02/01 20:30:19",
"updated_at": "2020/02/01 21:41:15"
}
t_type 表示交通工具、交通類型
t_type == 1 飛機
t_type == 2 火車
t_type == 3 地鐵
t_type == 4 長途客車/大巴
t_type == 5 公交車
t_type == 6 出租車
t_type == 7 輪船
t_type == 8 其它公共場所
't_type': '交通類型'
't_date': '日期'
't_no': '車次/車牌/航班號/場所名稱'
't_no_sub': '車廂'
't_pos_start': '出發站'
't_pos_end': '到達站'
't_memo': '車次附加描述'
't_start': '開始時間'
't_end': '結束時間'
'source': '線索來源'
'created_at': '提交時間'
'remark': '事件備註'
至此,同行程查詢工具的數據已經爬取完畢了,如何搜索,一定要將數據存庫或者放redis緩存中,然後寫一個查詢接口,就可以進行搜索時間+車次+地區的功能了,
下面放一下爬取要用到的工具類和完整代碼
三、工具類
用到的工具類,請戳鏈接:https://blog.csdn.net/qq_27471405/article/details/104140618
四、完整代碼
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.common.apiV2.beans.HttpPojo;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by yjl on 2020-02-01.
*/
@Service("WuhanService")
public class WuhanService {
public static void main(String[] args) {
getSameTripData();
}
/**
* 新型冠狀病毒肺炎確診患者同行程查詢工具
* @return
*/
public static String getSameTripData(){
String url="http://2019ncov.nosugartech.com/data.json?"+Math.floor(new Date().getTime()/1000/3600);
//模擬請求
HttpPojo httpPojo = new HttpPojo();
httpPojo.setHttpHost("2019ncov.nosugartech.com");
httpPojo.setHttpAccept("application/json, text/javascript, */*; q=0.01");
httpPojo.setHttpConnection("keep-alive");
httpPojo.setHttpUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
httpPojo.setHttpReferer("http://2019ncov.nosugartech.com/search.html");
httpPojo.setHttpOrigin("http://2019ncov.nosugartech.com/search.html");
Map paramObj = new HashMap();
String htmlResult = httpSendGet(url, paramObj, httpPojo); //整個html頁面
System.out.println(htmlResult);
//遍歷入庫或者存redis等操作
/*JSONObject dataJo = JSONObject.parseObject(htmlResult);
String data = dataJo.getString("data");//拿到所有數據
JSONArray array = JSONArray.parseArray(data);
for (int i = 0; i < array.size(); i++) {
JSONObject tripJo = JSONObject.parseObject(array.getString(i));
String t_no = tripJo.getString("t_no");
System.out.println("t_no:"+t_no);
//入庫操作
}*/
return htmlResult;
}
/**
* http請求
* @param url
* @param paramObj
* @param httpPojo
* @return
*/
private static String httpSendGet(String url, Map paramObj, HttpPojo httpPojo){
String result = "";
String urlName = url + "?" + parseParam(paramObj);
BufferedReader in=null;
try {
URL realURL = new URL(urlName);
URLConnection conn = realURL.openConnection();
//僞造ip訪問
String ip = randIP();
System.out.println("目前僞造的ip:"+ip);
conn.setRequestProperty("X-Forwarded-For", ip);
conn.setRequestProperty("HTTP_X_FORWARDED_FOR", ip);
conn.setRequestProperty("HTTP_CLIENT_IP", ip);
conn.setRequestProperty("REMOTE_ADDR", ip);
conn.setRequestProperty("Host", httpPojo.getHttpHost());
conn.setRequestProperty("accept", httpPojo.getHttpAccept());
conn.setRequestProperty("connection", httpPojo.getHttpConnection());
conn.setRequestProperty("user-agent", httpPojo.getHttpUserAgent());
conn.setRequestProperty("Referer",httpPojo.getHttpReferer()); //僞造訪問來源
conn.setRequestProperty("Origin", httpPojo.getHttpOrigin()); //僞造訪問域名
conn.connect();
Map<String, List<String>> map = conn.getHeaderFields();
for (String s : map.keySet()) {
//System.out.println(s + "-->" + map.get(s));
}
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += "\n" + line;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (in!=null){
try {
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return result;
}
/**
* 解析map
* @param paramObj
* @return
*/
public static String parseParam(Map paramObj){
String param="";
if (paramObj!=null&&!paramObj.isEmpty()){
for (Object key:paramObj.keySet()){
String value = paramObj.get(key).toString();
param+=(key+"="+value+"&");
}
}
return param;
}
/**
* 僞造ip地址
* @return
*/
public static String randIP() {
Random random = new Random(System.currentTimeMillis());
return (random.nextInt(255) + 1) + "." + (random.nextInt(255) + 1)
+ "." + (random.nextInt(255) + 1) + "."
+ (random.nextInt(255) + 1);
}
}
更多其他系列: