基于Java和XxlCrawler獲取各城市月度天氣情況實踐分享
前言
這篇文章主要來源于一個我們家小朋友的一個作業(yè),作業(yè)的主要內(nèi)容是要求小朋友做一個統(tǒng)計,在上半學(xué)期學(xué)習了統(tǒng)計知識,然后要結(jié)合生活實際進行統(tǒng)計應(yīng)用,因此有了這個作業(yè)。具體要求是在一定時間范圍內(nèi)(一個月),要求小朋友制作一個表格,需要記錄一個月內(nèi)每一天的天氣情況,比如陰晴雨雪。然后在這個記錄之上,要求統(tǒng)計出這個月不同的天氣有多少天?比如晴天多少天,雨天多少天,然后根據(jù)統(tǒng)計結(jié)果,計算這個月最多的天氣是什么?最少的是什么。這題目本身不難,只要每天都進行記錄的話,基本也就沒什么問題。然而,中間因為小朋友身體原因。沒有及時記錄,中間有一段時間沒有及時記錄。于是我們想,只能到網(wǎng)上查一下歷史天氣。
然而我發(fā)現(xiàn),小朋友中間有好幾天都忘了記錄,數(shù)據(jù)都有空缺。于是只能按照遺忘的日期來進行補數(shù)據(jù)。雖然最后把缺失的數(shù)據(jù)都補回來了。當時在想,還好只是一個月的數(shù)據(jù),如果要三個月,半年,甚至是一年的數(shù)據(jù),我還能一天一天的找數(shù)據(jù)不成。作為技術(shù)人,需要用一點技術(shù)手段來解決這個問題。
本文主要講解使用Java開發(fā)語言,使用XxlCrawler框架進行智能的某城市月度天氣抓取實踐開發(fā)。文章首先介紹目標網(wǎng)站的相關(guān)頁面及目標數(shù)據(jù)的元素,然后講解在信息獲取過程的一些參數(shù)配置以及問題應(yīng)對,最后結(jié)合實際代碼實際抓取一個城市(以長沙為例)某月度天氣數(shù)據(jù)。通過本文,您可以更加了解XxlCrawler的具體使用,知道如何解決頁面返回慢的情況下如何通過超時參數(shù)來控制數(shù)據(jù)返回的問題,如果您是氣象人,需要氣象數(shù)據(jù),則可以通過本文來獲取想研究的地域的歷史天氣數(shù)據(jù)。
一、歷史數(shù)據(jù)獲取
由于我們需要歷史數(shù)據(jù),因此需要找到歷史數(shù)據(jù)源網(wǎng)站。關(guān)于天氣的數(shù)據(jù)有很多網(wǎng)站可以提供。比較權(quán)威的就是國家的官方網(wǎng)站。這里呢,分享一個天氣后報網(wǎng)站天氣后報網(wǎng),這個網(wǎng)站上可以提供城市的天氣信息。本節(jié)主要介紹這個網(wǎng)站的內(nèi)容和具體月度天氣的頁面。為下一步的信息獲取做準備。
1、關(guān)于天氣后報
在瀏覽器中,輸入它的官方網(wǎng)站:http://www.tianqihoubao.com/??梢钥吹剿墓俜浇缑?。
在上方的導(dǎo)航欄中,點擊歷史天氣,可以切換到歷史天氣查詢列表,默認按照行政區(qū)劃列表的形式展示。
根據(jù)我們的需要,比如(長沙),點擊我們感興趣的城市,打開城市歷史天氣列表:
然后打開對應(yīng)的月度天氣連接,24年4月份。
http://www.tianqihoubao.com/lishi/changsha/month/202404.html
這是實際的網(wǎng)頁地址,請注意這個地址,這里其實有兩個變量,第一個是城市,也就是地址信息中的changsha,另外一個是時間即202404,通過網(wǎng)站靜態(tài)化之后,這些信息都是有規(guī)律的。因此我們可以采用XxlCrawler來自動獲取。
2、信息界面分析
在找到了信息源之后,我們需要分析一些網(wǎng)頁的結(jié)構(gòu),網(wǎng)頁信息很多,我們只關(guān)心目標數(shù)據(jù)。這里只需要把表格中的幾個關(guān)鍵信息提取出來即可。比如日期、天氣狀況、氣溫信息、風力風向信息。這些關(guān)鍵的信息都是在一個表格中展示出來的。在頁面中打開調(diào)試窗口,來看一下結(jié)構(gòu):
首先來看一下網(wǎng)頁結(jié)構(gòu),其主要的div是綁定在一個id='content'的網(wǎng)頁元素下的。同時下面的數(shù)據(jù)是存在在標準的table中,因此我們只需要將table中的tr中循環(huán)提取出來即可。
二、數(shù)據(jù)的提取開發(fā)
在明確了數(shù)據(jù)來源的網(wǎng)頁結(jié)構(gòu)之后,這一節(jié)我們來進行實際的數(shù)據(jù)提取的開發(fā)。通過XxlCrawler組件來獲取信息。本小節(jié)著重講解代碼的設(shè)計與實現(xiàn)。
1、PageVo的定義
熟悉XxlCrawler的朋友知道,PageVO是解析頁面的一個對象??蚣茉谧x取到頁面的信息后,會自動的將信息按照PageVO的配置,解析到實體類中。因此需要對PageVO進行定義。
@PageSelect(cssQuery = "#content >table >tbody >tr") @AllArgsConstructor @NoArgsConstructor public static class PageVo { @PageFieldSelect(cssQuery=" >td:eq(0)") @Excel(name = "日期") private String day; @PageFieldSelect(cssQuery = ">td:eq(1)") @Excel(name = "天氣狀況") private String weatherInfo; @PageFieldSelect(cssQuery = ">td:eq(2)") @Excel(name = "最低氣溫/最高氣溫") private String weatherTemp; @PageFieldSelect(cssQuery = ">td:eq(3)") @Excel(name = "風力風向(夜間/白天)") private String weatherWind; }
在PageVO的定義過程中,我們使用了三個注解,第一個是@PageSelect(cssQuery = "#content >table >tbody >tr"),這個注解是用來進行頁面抓取綁定的。第二個是@PageFieldSelect(cssQuery=" >td:eq(0)"),這個主要是用來進行具體的屬性信息綁定,即解析哪個信息,設(shè)置到哪個屬性當中去,在循環(huán)中特別好用。不用向之前那樣,自己去解析。第三個是@Excel(name = "日期"),這個跟信息獲取關(guān)系不大,只是用來最后將獲取的信息寫入到Excel表格中。當然,結(jié)合實際的需求,您可以把數(shù)據(jù)寫入到數(shù)據(jù)庫中,這樣子可以在后期在需要的時候進行查詢進行分析。
2、屬性定義
按照JavaOOP的設(shè)計思想,這里我們將一些信息封裝起來,比如User-Agent還有公共的請求地地址等統(tǒng)一定義,在進行信息抓取時可以直接使用。關(guān)鍵代碼如下:
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"; private List<PageVo> weatherList = new ArrayList<PageVo>(); private static final String COMMON_URL = "http://www.tianqihoubao.com/lishi/changsha/month/";
weatherList就是用來保存所有的天數(shù)數(shù)據(jù)的,在程序的最后可以用來保存數(shù)據(jù)或者持久化的作用。
3、實際信息抓取
這里來定義實際信息抓取對象的配置,以及實際啟動邏輯。
@Test public void fetchWeaterInfo() { int year = 2023; int month = 9; // 月份從 0 開始,3 表示4月份 String monthStr = ""; monthStr += month < 10 ? "0" + month : month; String targetUrl = COMMON_URL + year + monthStr + ".html"; System.out.println(targetUrl); // 構(gòu)造爬蟲 XxlCrawler crawler = new XxlCrawler.Builder() .setUrls(targetUrl) .setAllowSpread(false)// 不允許擴散爬取 .setThreadCount(3) .setPauseMillis(3000) .setUserAgent(USER_AGENT)//設(shè)置user_agent .setIfPost(false) .setFailRetryCount(3)// 重試三次 .setTimeoutMillis(1000 * 12)//超時時間,有些網(wǎng)站加載慢,一定要加這個時間 .setPageParser(new PageParser<PageVo>() { @Override public void parse(Document html, Element pageVoElement, PageVo pageVo) { //System.out.println(pageVoElement); weatherList.add(pageVo); } }).build(); crawler.start(true);// 啟動 // excel工具包 weatherList.remove(0);//把第一行表頭移除掉 ExcelUtil<PageVo> util = new ExcelUtil<PageVo>(PageVo.class); util.exportExcel(weatherList, year + "年" + month + "月天氣情況表"); System.out.println("finished..."); }
這里需要注意的是,信息抓取器,每次得到的一個tbody中的一行,即tr的數(shù)據(jù)。我們需要將所有的數(shù)據(jù)解析完成之后,統(tǒng)一存放到一個List當中。實現(xiàn)月度的數(shù)據(jù)搜集,同時第一行是表頭數(shù)據(jù)。需要剔除。因此,在寫入到Excel之前,要將第一行刪除,
weatherList.remove(0);//把第一行表頭移除掉
三、信息抓取調(diào)試以及可能的問題
這里分享實際的信息獲取結(jié)果,對抓取的信息進行綜合展示。同時這里簡單分享在信息獲取過程中可能遇到的問題和解決方案。
1、信息獲取成果
將上述代碼運行后,可以在控制中看到以下輸出信息:
http://www.tianqihoubao.com/lishi/changsha/month/202309.html 09:42:29.027 [main] INFO com.xuxueli.crawler.rundata.strategy.LocalRunData - >>>>>>>>>>> xxl-crawler addUrl success, link: http://www.tianqihoubao.com/lishi/changsha/month/202309.html 09:42:29.035 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler start ... 09:42:29.038 [pool-1-thread-1] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler, process link : http://www.tianqihoubao.com/lishi/changsha/month/202309.html 09:42:33.634 [pool-1-thread-1] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler is finished. 09:42:33.635 [pool-1-thread-2] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted. 09:42:33.635 [pool-1-thread-3] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted. 09:42:33.635 [pool-1-thread-1] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler stop. 09:42:33.636 [pool-1-thread-1] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted. finished...
這里提示,信息抓取完成,同時我們將數(shù)據(jù)寫入到了Excel當中,找到目標文件夾,來看一下實際的效果。
日期 | 天氣狀況 | 最低氣溫/最高氣溫 | 風力風向(夜間/白天) |
2024年04月01日 | 小雨 /大雨 | 20℃ / 26℃ | 東南風 1-3級 /南風 1-3級 |
2024年04月02日 | 大雨 /小雨 | 16℃ / 26℃ | 西風 1-3級 /北風 1-3級 |
2024年04月03日 | 中雨 /小雨 | 15℃ / 18℃ | 北風 1-3級 /北風 1-3級 |
2024年04月04日 | 中雨 /小雨 | 13℃ / 15℃ | 西北風 1-3級 /北風 1-3級 |
2024年04月05日 | 小雨 /小雨 | 13℃ / 16℃ | 西北風 1-3級 /北風 1-3級 |
2024年04月06日 | 小雨 /小雨 | 14℃ / 16℃ | 北風 1-3級 /北風 1-3級 |
2024年04月07日 | 小雨 /小雨 | 14℃ / 19℃ | 北風 1-3級 /西北風 1-3級 |
2024年04月08日 | 多云 /多云 | 15℃ / 24℃ | 北風 1-3級 /北風 1-3級 |
2024年04月09日 | 多云 /小雨 | 15℃ / 23℃ | 東北風 1-3級 /東風 1-3級 |
2024年04月10日 | 多云 /小雨 | 17℃ / 22℃ | 東風 1-3級 /東北風 1-3級 |
2024年04月11日 | 小雨 /小雨 | 18℃ / 21℃ | 北風 1-3級 /北風 1-3級 |
2024年04月12日 | 陰 /小雨 | 18℃ / 25℃ | 東南風 1-3級 /東南風 1-3級 |
2024年04月13日 | 中雨 /小雨 | 20℃ / 26℃ | 東南風 1-3級 /南風 1-3級 |
2024年04月14日 | 小雨 /多云 | 20℃ / 28℃ | 東北風 1-3級 /東南風 1-3級 |
2024年04月15日 | 小雨 /中雨 | 21℃ / 31℃ | 南風 1-3級 /東南風 1-3級 |
2024年04月16日 | 暴雨 /中雨 | 20℃ / 26℃ | 西風 1-3級 /西風 1-3級 |
2024年04月17日 | 小雨 /陰 | 19℃ / 23℃ | 西北風 1-3級 /北風 1-3級 |
2024年04月18日 | 多云 /小雨 | 19℃ / 27℃ | 東南風 1-3級 /東南風 1-3級 |
2024年04月19日 | 中雨 /陰 | 18℃ / 24℃ | 東南風 1-3級 /北風 1-3級 |
2024年04月20日 | 小雨 /小雨 | 19℃ / 24℃ | 北風 1-3級 /西北風 1-3級 |
2024年04月21日 | 陰 /多云 | 17℃ / 24℃ | 東風 1-3級 /北風 1-3級 |
2024年04月22日 | 小雨 /陰 | 19℃ / 24℃ | 西北風 1-3級 /西北風 1-3級 |
2024年04月23日 | 多云 /多云 | 18℃ / 27℃ | 北風 1-3級 /北風 1-3級 |
2024年04月24日 | 多云 /小雨 | 19℃ / 27℃ | 東北風 1-3級 /東風 1-3級 |
2024年04月25日 | 中雨 /多云 | 19℃ / 25℃ | 東風 1-3級 /東風 1-3級 |
2024年04月26日 | 多云 /多云 | 19℃ / 30℃ | 西北風 1-3級 /東南風 1-3級 |
2024年04月27日 | 中雨 /小雨 | 20℃ / 28℃ | 東北風 1-3級 /西南風 1-3級 |
2024年04月28日 | 多云 /小雨 | 20℃ / 29℃ | 北風 1-3級 /東北風 1-3級 |
2024年04月29日 | 中雨 /大雨 | 18℃ / 25℃ | 西風 1-3級 /西北風 1-3級 |
2024年04月30日 | 小雨 /多云 | 14℃ / 18℃ | 北風 1-3級 /北風 1-3級 |
大家可以對比原來的網(wǎng)頁地址,可以看到表格獲取的信息與網(wǎng)頁一致。這里的實例僅提供一個例子,拋磚引玉,大家可以結(jié)合自己的實際工作。獲取更多的天氣信息。
2、關(guān)于超時的問題
XxlCrawler的默認超時時間是5秒(5000ms),即5秒鐘內(nèi)數(shù)據(jù)沒有返回則超時。其定義如下:
private volatile int timeoutMillis = XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT; // 超時時間,毫秒 // timeout default, ms public static final int TIMEOUT_MILLIS_DEFAULT = 5*1000;
在默認的情況下,頁面經(jīng)常超時,請求時會報以下的錯誤:
http://www.tianqihoubao.com/lishi/changsha/month/202404.html 11:03:27.685 [main] INFO com.xuxueli.crawler.rundata.strategy.LocalRunData - >>>>>>>>>>> xxl-crawler addUrl success, link: http://www.tianqihoubao.com/lishi/changsha/month/202404.html 11:03:27.693 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler start ... 11:03:27.695 [pool-1-thread-2] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler, process link : http://www.tianqihoubao.com/lishi/changsha/month/202404.html 11:03:32.697 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler still running ... 11:03:33.456 [pool-1-thread-2] ERROR com.xuxueli.crawler.util.JsoupUtil - Read timeout java.net.SocketTimeoutException: Read timeout at org.jsoup.internal.ConstrainableInputStream.read(ConstrainableInputStream.java:58) at sun.nio.cs.StreamDecoder.readBytes(Unknown Source) at sun.nio.cs.StreamDecoder.implRead(Unknown Source) at sun.nio.cs.StreamDecoder.read(Unknown Source) at java.io.InputStreamReader.read(Unknown Source) at java.io.BufferedReader.fill(Unknown Source) at java.io.BufferedReader.read1(Unknown Source) at java.io.BufferedReader.read(Unknown Source) at org.jsoup.parser.CharacterReader.bufferUp(CharacterReader.java:87) at org.jsoup.parser.CharacterReader.current(CharacterReader.java:246) at org.jsoup.parser.TokeniserState$1.read(TokeniserState.java:12) at org.jsoup.parser.Tokeniser.read(Tokeniser.java:62) at org.jsoup.parser.TreeBuilder.runParser(TreeBuilder.java:86) at org.jsoup.parser.TreeBuilder.parse(TreeBuilder.java:61) at org.jsoup.parser.Parser.parseInput(Parser.java:51) at org.jsoup.helper.DataUtil.parseInputStream(DataUtil.java:218) at org.jsoup.helper.HttpConnection$Response.parse(HttpConnection.java:962) at org.jsoup.helper.HttpConnection.get(HttpConnection.java:355) at com.xuxueli.crawler.util.JsoupUtil.load(JsoupUtil.java:77) at com.xuxueli.crawler.loader.strategy.JsoupPageLoader.load(JsoupPageLoader.java:17) at com.xuxueli.crawler.thread.CrawlerThread.processPage(CrawlerThread.java:167) at com.xuxueli.crawler.thread.CrawlerThread.run(CrawlerThread.java:84) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source)
在網(wǎng)頁中驗證以下請求時間,請注意打開F12進行頁面請求的時間跟蹤:
可以看到頁面 ,頁面加載大約花了11.93秒,接近12秒。因此其默認的5秒超時設(shè)置是不夠的。具體的響應(yīng)時間,請按照大家的實際情況合理設(shè)置。把超時時間延長后,就不會出現(xiàn)這個錯誤了。
四、總結(jié)
以上就是本文的主要內(nèi)容,本文主要講解使用Java開發(fā)語言,使用XxlCrawler框架進行智能的某城市月度天氣抓取實踐開發(fā)。文章首先介紹目標網(wǎng)站的相關(guān)頁面及目標數(shù)據(jù)的元素,然后講解在信息獲取過程的一些參數(shù)配置以及問題應(yīng)對,最后結(jié)合實際代碼實際抓取一個城市(以長沙為例)某月度天氣數(shù)據(jù)。通過本文,您可以更加了解XxlCrawler的具體使用,知道如何解決頁面返回慢的情況下如何通過超時參數(shù)來控制數(shù)據(jù)返回的問題,如果您是氣象人,需要氣象數(shù)據(jù),則可以通過本文來獲取想研究的地域的歷史天氣數(shù)據(jù)。行文倉促,定有不足之處,歡迎各位專家朋友在評論區(qū)中批評指正,萬分榮幸。技術(shù)人通過自己的技術(shù)來解決一點生活問題,技術(shù)讓生活更美好。
以上就是基于Java和XxlCrawler獲取各城市月度天氣情況實踐分享的詳細內(nèi)容,更多關(guān)于Java XxlCrawler獲取天氣情況的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Mybatis實現(xiàn)單個和批量定義別名typeAliases
這篇文章主要介紹了Mybatis實現(xiàn)單個和批量定義別名typeAliases,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09SpringData JPA審計功能(@CreatedDate與@LastModifiedDate)實現(xiàn)
Spring Data JPA的審計功能提供了一種強大而靈活的機制,用于自動跟蹤實體的創(chuàng)建和修改信息,通過使用@CreatedDate和@LastModifiedDate注解,開發(fā)者可以輕松地實現(xiàn)時間審計,感興趣的可以了解一下2025-04-04完美解決gson將Integer默認轉(zhuǎn)換成Double的問題
下面小編就為大家?guī)硪黄昝澜鉀Qgson將Integer默認轉(zhuǎn)換成Double的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03Java的idea連接mongodb數(shù)據(jù)庫的詳細教程
這篇文章主要介紹了Java的idea連接mongodb數(shù)據(jù)庫的詳細教程,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11基于SpringBoot bootstrap.yml配置未生效的解決
這篇文章主要介紹了基于SpringBoot bootstrap.yml配置未生效的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10mybatis-plus數(shù)據(jù)權(quán)限實現(xiàn)代碼
這篇文章主要介紹了mybatis-plus數(shù)據(jù)權(quán)限實現(xiàn),結(jié)合了mybatis-plus的插件方式,做出了自己的注解方式的數(shù)據(jù)權(quán)限,雖然可能存在一部分的局限性,但很好的解決了我們自己去解析SQL的功能,需要的朋友可以參考下2023-06-06