因為本人對爬蟲比較感興趣,加上之前也寫過一些簡單的python爬蟲,所以在學完java基礎后寫了一個簡單的網絡圖片爬蟲。廢話不多說直接上過程代碼。(爬取的圖源來自花瓣網:https://huaban.com/boards/favorite/beauty/)
源url頁面分析
拿到爬取的源url,首先是分析頁面哪些東西是要爬取的,這個頁面是美女分類的畫板頁面,這里我們要爬的就是要爬取某個畫板下面的所有圖片。這里為了簡單爬取我就選取了該頁面推薦的幾個畫板。查看本頁面源碼可以很快找到推薦畫板的url資源,如下圖。
可以看到要爬取目標資源就存在這個app.page["suggests"]里面,可以通過正則拿到這些url,然后依次去訪問這些url,得到畫板頁面。
畫板url的爬取
這里先寫一個靜態的獲取頁面html的方法
public static StringBuffer getHtml(String url) throws Exception{ URL url1 = new URL(url); URLConnection connection = url1.openConnection(); InputStream is = connection.getInputStream(); BufferedReader bw = new BufferedReader(new InputStreamReader(is)); StringBuffer sb = new StringBuffer(); while (bw.ready()){ sb.append(bw.readLine()).append("\n"); } bw.close(); is.close(); return sb; }
編寫爬取畫板url的正則,如下
tring suggestsRegex = "app.page\\[\"suggests\"\\] = \\{.*\\}"; String urlRegex = "\"url\":\".*?\""; StringBuffer html = Util.getHtml("https://huaban.com/boards/favorite/beauty/"); Matcher suggestsMatcher = Pattern.compile(suggestsRegex).matcher(html); while (suggestsMatcher.find()){ Matcher urlMatcher = Pattern.compile(urlRegex).matcher(suggestsMatcher.group()); while (urlMatcher.find()){ System.out.println(urlMatcher.group()); } }
可以得到下面的結果:
但是這些url並不全是我們需要的畫板url,比如上面第三條url會跳轉到另一個分類頁面,而且有些url協議為http有些為https,這里測試發現協議為http的都會重定向到其對應的https頁面,所以這里我們為了方便提取url,只提取目標中的畫板id,就是數字部分,然后手動添加其余的部分,修改上面的部分代碼如下。
while (urlMatcher.find()) { // System.out.println(urlMatcher.group()); String urlStr = urlMatcher.group(); if (urlStr.contains("boards")) { Matcher matcherId = Pattern.compile("[\\d]+").matcher(urlStr); String id = ""; while (matcherId.find()) { id = matcherId.group(); } String url = "https://huaban.com/boards/" + id; System.out.println(url); } }
此時就得到了推薦畫板的url了。
畫板頁面分析
這里用getHtml方法得到的畫板頁面html和在瀏覽器中查看的源碼並不相同,其中源碼部分的script代碼被解析為了html代碼被返回回來了。所以這里我們只能看控制台打印回來的代碼來找到圖片的url。此處就不作太多介紹,具體可自行嘗試查看。
圖片url的爬取
這里也是采用正則來爬(網上有選擇器的方法來爬取目標資源,可自行百度),先是獲取所有img標簽的內容再進一步正則查詢其中符合圖片url特征的內容。如下
String get_img_regex = "<img src=\"//hbimg.*?/>"; String get_src_regex = "\"//hbimg.huabanimg.com/.*?\""; StringBuffer html = Util.getHtml("https://huaban.com/boards/17375733"); Matcher matcherImg = Pattern.compile(get_img_regex).matcher(html); while (matcherImg.find()){ Matcher matcherSrc = Pattern.compile(get_src_regex).matcher(matcherImg.group()); while (matcherSrc.find()){ System.out.println(matcherSrc.group()); } }
通過測試發現末尾位sq75sf的是頭像圖url,末尾為fw236的才是我們需要的圖片url,不過是小圖,我們發現大圖(瀏覽器上點開單個圖片頁面即可查看大圖url)的url只有末尾參數與小圖url不同(大圖末尾是fw658),修改上面部分代碼如下
while (matcherSrc.find()){ String srcStr = matcherSrc.group(); if (srcStr.contains("fw236")){ String srcUrl = srcStr.substring(1,srcStr.length()-1).replace("fw236","fw658"); System.out.println(srcUrl); } }
最后將得到的數據用列表封裝並返回即可。
圖片下載
URL url = new URL("http://hbimg.huabanimg.com/3bd402c57a727148fce86c193c9d5e93fb48b14b4d760-wF9Y7Z_fw658"); InputStream is = url.openStream(); FileOutputStream fos = new FileOutputStream("src/test.png"); byte buf[] = new byte[1024]; int length = 0; while ((length=is.read(buf))!=-1){ fos.write(buf,0,length); } fos.close(); is.close();
代碼優化與完善
這里簡單的說一下程序優化的方案。由於有多個畫板,所以每個畫板可以開啟一個線程進行爬取。還有就是每個畫板大約只能爬到40張左右圖片,那是因為頁面采用Ajax加載資源(這個我也不太懂,可自行百度),可用代碼模擬加載數據進而獲取到所有圖片。(這里每次加載請求的參數是每個頁面最后一張圖片的id,可自行嘗試完成)
寫在最后
因為本人還是個java初學者菜鳥,所以代碼肯定是有漏洞和不足的地方歡迎大家指出共同學習,謝謝。
項目源碼:https://github.com/zengtao614/JavaCrawler