1. 程式人生 > >使用Jsoup抓取資料

使用Jsoup抓取資料

問題

最近公司的市場部分佈了一個問題,到一個網站擷取一下醫院的資料。剛好我也被安排做。後來,我發現為何不用指令碼去抓取呢?
抓取的資料如下:
這裡寫圖片描述

Jsoup的使用實戰程式碼

結構

Created with Raphaël 2.1.0開始建立執行緒池jsoup讀取網頁解析Element寫入sqlite結束
  • java程式碼
public class GetDoctorInfo {

    public GetDoctorInfo() {

        ExecutorService threadPool = Executors.newFixedThreadPool(5
); //43有問題 //73有問題 for (int i = 1; i <= 100; i++) { String path = "http://so.haodf.com/index/search?type=hospitalfaculty&p=" + i + "&kw=%B8%BE%B2%FA%BF%C6"; threadPool.execute(new GetDoctorRun(path)); } threadPool.shutdown(); } public
static void main(String[] arg) { new GetDoctorInfo(); } public static synchronized void printInfo(String sql) { System.out.println(sql); } public static String trans(String input) { String value; value = input.replaceAll("<td>", "").replaceAll("</td>"
, "").replaceAll("&nbsp;", "").replaceAll(" 地址地圖:", ""); return value; } /** * 獲取醫生的執行緒 */ public class GetDoctorRun implements Runnable { final String mURL; public GetDoctorRun(String mURL) { this.mURL = mURL; } @Override public void run() { try { Document doc = null; try { // doc = (Document) Jsoup.parse(new URL("http://so.haodf.com/index/search?type=hospitalfaculty&p=99&kw=%B8%BE%B2%FA%BF%C6") // , 1000); doc = (Document) Jsoup.parse(new URL(mURL), 3000); } catch (IOException e) { e.printStackTrace(); } //定位到列表 Elements elements = doc.getElementsByClass("list"); Elements childElements = elements.get(0).getAllElements(); Element child = childElements.get(3); //獲得所有的超連結的資料 Elements aLinks = child.getElementsByTag("a"); ArrayList<String> name = new ArrayList<>(); ArrayList<String> address = new ArrayList<>(); for (int i = 1; i <= aLinks.size(); i++) { Element e = aLinks.get(i - 1); if (e.attr("target").equals("_blank")) { //排除 科室介紹 //排除 門診時間 if (!e.text().equals("科室介紹") && !e.text().equals("門診時間")) { // System.out.println("--" + e.text()); if (i % 2 == 0) { if (e.text().equals("") || e.text() == null) { address.add(""); } else { address.add(e.text()); } } else { if (e.text().equals("") || e.text() == null) { name.add(""); } else { name.add(e.text()); } } } } } //將長連線的內容刪除 child.select("a").remove(); child.select("span").remove(); child.select("br").remove(); String tran = trans(child.toString()); // System.out.println(tran); String[] phones = tran.substring(" 電  話:".length(), tran.length() - 1).split("電  話:"); System.out.println(); System.out.println(); System.out.println(); for (int i = 0; i < name.size(); i++) { // System.out.println(phones[i]); // //INSERT INTO info(hospital_name,address,phone) VALUES ('gg','hhh','ddd'); StringBuffer bufferValue = new StringBuffer("INSERT INTO info(hospital_name,address,phone) VALUES ("); //醫院名 bufferValue.append("'").append(name.get(i)).append("'"); //醫院地址 bufferValue.append(",'").append(address.get(i)).append("'"); //醫院的電話 bufferValue.append(",'").append(phones[i].trim()).append("');"); printInfo(bufferValue.toString()); } if (name.size() != 10) { System.out.println("name==" + mURL); } if (address.size() != 10) { System.out.println("address=" + mURL); } if (phones.length != 10) { System.out.println("phone=" + phones.length + " " + mURL); } } catch (Exception e) { e.printStackTrace(); } } } }
  • Terminal寫入sqlte

.open hospital.db
sqlite3 -init sql

總結

jsoup的使用很簡單,有點像解析xml。不過結果很好的,因為5,6個人的工作就被這個簡單的程式碼實現了。解析技巧有一個儘量清除不必要的標籤。如程式碼:

       child.select("a").remove();
       child.select("span").remove();
       child.select("br").remove();
  • 學會用指令碼收集資料
  • 注意多謝執行緒併發的安全,要檢驗,要不很易出錯
  • 對於多執行緒的問題關鍵是要確保你的內容不被競爭弄亂,所以提取出來進行程式碼塊是很重要的。

最後補充一下最終的效果如下圖