今天目標是點擊租物列表的物件,進入頁面取得詳細資料。
將很多變數、函數都進行了重新命名,程式碼也改了很多,希望不會影響閱讀。
調整了爬蟲Service,現在如下
public interface RentalCrawlerService {
//取得最新的591租屋目錄資訊
List<RentalCatalog> fetchLatestRentalCatalog();
//取得591租屋詳細資訊
RentalDetail fetchRentalDetail(RentalCatalog rentalCatalog);
}
現在爬蟲Service有兩個函數
所以我們要取得所有的詳細資訊就是,點擊每個目錄,進去進行二次爬取資料。
@Override
public void run(ApplicationArguments args) throws Exception {
List<RentalCatalog> list = rentalCrawlerService.fetchLatestRentalCatalog();
list.stream().forEach(obj ->rentalCrawlerService.fetchRentalDetail(obj));
}
因為兩隻函數都會用到爬蟲相關的方法,故移到初始化時進行。
程式結束時,再將driver關閉。
private WebDriver driver;
@PostConstruct
public void init() {
webDriverInit();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
driver.quit();
}));
}
fetchRentalDetail的實作
就是使用連結,進行二次爬取。
@Override
public RentalDetail fetchRentalDetail(RentalCatalog rentalCatalog) {
log.info("Starting to fetch rental detail data...");
String detailUrl = rentalCatalog.getLink();
Document doc = getJsoupDoc(detailUrl);
RentalDetail rentalDetail = parseRentalDetail(doc);
return rentalDetail;
}
最麻煩的其實就是解析資料。
一樣使用Jsoup的選擇器選取資料。
要注意的是,提供設備591是使用class取控制的。
這個是有陽台的
<dl class="" data-v-cfafc3c0="">
<dt data-v-cfafc3c0="">
<i class="ic-house house-balcony" data-v-cfafc3c0=""></i>
</dt>
<dd class="text" data-v-cfafc3c0="">2陽台</dd>
</dl>
這個是沒有陽台的
<dl class="del" data-v-cfafc3c0="">
<dt data-v-cfafc3c0="">
<i class="ic-house house-balcony" data-v-cfafc3c0=""></i>
</dt>
<dd class="text" data-v-cfafc3c0="">陽台</dd>
</dl>
差別在於
dl class="del" 跟 dl class="" 而已
知道條件後就可以寫出程式碼。
private RentalDetail parseRentalDetail(Document doc) {
RentalDetail rentalDetail = new RentalDetail();
// 租住說明
String rentalDescription = doc.select("div.service-cate:has(i.icon-desc) span").text();
rentalDetail.setRentalDescription(rentalDescription);
// 房屋守則
String houseRules = doc.select("div.service-cate:has(i.icon-rule) span").text();
rentalDetail.setHouseRules(houseRules);
// 設備列表
rentalDetail.setHasFridge(!doc.select("dl:has(i.house-fridge-big)").hasClass("del"));
rentalDetail.setHasWasher(!doc.select("dl:has(i.house-washer)").hasClass("del"));
rentalDetail.setHasTv(!doc.select("dl:has(i.house-tv)").hasClass("del"));
rentalDetail.setHasCold(!doc.select("dl:has(i.house-cold)").hasClass("del"));
rentalDetail.setHasHeater(!doc.select("dl:has(i.house-heater)").hasClass("del"));
rentalDetail.setHasBed(!doc.select("dl:has(i.house-bed)").hasClass("del"));
rentalDetail.setHasCloset(!doc.select("dl:has(i.house-closet)").hasClass("del"));
rentalDetail.setHasFourth(!doc.select("dl:has(i.house-fourth)").hasClass("del"));
rentalDetail.setHasWifi(!doc.select("dl:has(i.house-wifi-big)").hasClass("del"));
rentalDetail.setHasGas(!doc.select("dl:has(i.house-gas)").hasClass("del"));
rentalDetail.setHasSofa(!doc.select("dl:has(i.house-sofa)").hasClass("del"));
rentalDetail.setHasTable(!doc.select("dl:has(i.house-table)").hasClass("del"));
rentalDetail.setHasBalcony(!doc.select("dl:has(i.house-balcony)").hasClass("del"));
rentalDetail.setHasLift(!doc.select("dl:has(i.house-lift)").hasClass("del"));
rentalDetail.setHasParking(!doc.select("dl:has(i.house-parking)").hasClass("del"));
log.info(rentalDetail.getInfo());
return rentalDetail;
}
package tw.grass.rental_crawler.model;
import lombok.Data;
@Data
public class RentalDetail {
String rentalDescription;
String houseRules;
String address;
String price;
String floorAndArea;
boolean hasFridge;
boolean hasWasher;
boolean hasTv;
boolean hasCold;
boolean hasHeater;
boolean hasBed;
boolean hasCloset;
boolean hasFourth;
boolean hasWifi;
boolean hasGas;
boolean hasSofa;
boolean hasTable;
boolean hasBalcony;
boolean hasLift;
boolean hasParking;
}
現在我們已經爬取到我們要得租屋資訊了,但是目錄資訊那邊其實有分頁的問題要處理。
不過明天應該會先建立資料庫,否則不知道哪些資料是新的還舊的。