之前寫了一篇selenium + ChromeDriver的一些入門的知識,這篇博客里面找了啟信寶這個網站,簡單的進行了一個實戰練習。本篇博客的結構如下:
首先會給出一些使用
selenium + ChromeDriver的入門的一些友情鏈接
其次講解一下本人在爬取網站的一些思路和流程
最后給
出github地址並總結經驗。
1. 友情鏈接
環境配置以及入門知識參考我的之前一篇博客:
詳細使用方式參考webDriver中文社區:
使用過程的常見異常參考他人博客:
2. 爬取思路及流程

整體的爬取思路見上圖,分為兩個流程的原因是:在點擊頁面去向另一個頁面時會出現讓你登陸或者數據驗證碼的情況。如果每一步都要進行判斷不好管理,還不如直接放在一個方法里面進行管理。只要每次有點擊頁面鏈接或者按鈕的情況都進入到頁面判斷及處理流程中去。通過這個方法判斷你新進入的頁面是什么情況,並且對不同的頁面進行不同的處理。下面對每個步驟進行詳細講解
2.1 點擊登錄


1 //去登陸頁面並且登錄 2 public static void toLoginAndLogin(WebDriver driver) { 3 //1、去登陸頁面 4 List<WebElement> elements = driver.findElements(By.cssSelector("div.pull-right a")); 5 //2、通過下標得到對應的登錄鏈接 6 WebElement loginElement = elements.get(elements.size() - 1); 7 loginElement.click(); 8 //2、該方法判斷當前頁面是登錄頁面,則進行登錄 9 CompanyInfoPageHandle.handleDifferentPage(driver); 10 }
2.2 搜索公司


//查詢公司名稱 public static void searchCompanyName(WebDriver driver, String CompanyName) { //1、查詢公司名稱 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //2、選取輸入框 WebElement search = driver.findElement(By.cssSelector("input[placeholder=\"請輸入企業名、人名、產品名等關鍵詞,多關鍵詞用空格隔開,如:上海 平安\"]")); search.sendKeys(CompanyName); //3、選取按鈕 WebElement submit = driver.findElement(By.cssSelector("i.input-group-addon.search-btn.icon.icon-search")); submit.click(); //4、判斷當前頁面的情況並進行處理 CompanyInfoPageHandle.handleDifferentPage(driver); }
2.3 爬取當前數據

/** * 保存信息 * @param driver * @param companyName */ private void saveResult(WebDriver driver, String companyName) { try { Thread.sleep(2000); //1、首先遍歷每行的公司信息 List<WebElement> companyElementList = driver.findElements(By.cssSelector("div.col-xs-24.padding-v-1x.margin-0-0x.border-b-b4.company-item")); //2、保存當前一行公司的信息 for (WebElement companyElement : companyElementList) {//保存信息 try { List<WebElement> companyInfoElementList = companyElement.findElements(By.cssSelector("div")); List<String> infoList = new ArrayList<>(); for (WebElement companyInfo : companyInfoElementList) { infoList.add(companyInfo.getText().replace("\n", "")); } String result = String.join("\t", infoList); FileUtils.saveLineAppend(companyName + ".txt", result); } catch (Exception e) { continue; } } } catch (Exception e) { e.printStackTrace(); } }
2.4 頁面判斷及處理
在之前的過程中,只要有點擊事件觸發則需要判斷觸發之后的頁面是什么頁面,才能夠對當前的頁面進行處理。主要分為兩個過程,第一步判斷當前頁面是什么,第二步對不同的頁面有不同的處理方式,具體見下面代碼:

/** * 用來判別頁面的情況 */ public class CompanyInfoPageClassification { /** * 頁面判斷的主方法,用來判斷當前的頁面是什么頁面 * @param driver * @return */ public static String PageClassificationMain(WebDriver driver){ if (isVerificationCodePage(driver)){ return "驗證碼"; } if (is404Page(driver)){ return "404"; } if (isLoginPage(driver)){ return "登錄"; } return "正常"; } /** * 判斷當前頁面是否是驗證碼頁面 * @param driver * @return */ private static boolean isVerificationCodePage(WebDriver driver){ List<WebElement> buttonList = driver.findElements(By.cssSelector("button.btn4")); if (buttonList.size() != 0 && buttonList.get(0).getText().equals("點擊按鈕進行驗證")) { return true; } else { return false; } } /** * 判斷當前頁面是否是404 * @param driver * @return */ private static boolean is404Page(WebDriver driver){ List<WebElement> buttonList = driver.findElements(By.cssSelector("div.error-container.error-404")); if (buttonList.size() != 0 ) { return true; } else { return false; } } /** * 判斷當前頁面是否是登錄頁面 * @param driver * @return */ private static boolean isLoginPage(WebDriver driver){ List<WebElement> buttonList = driver.findElements(By.cssSelector("input[placeholder=\"請輸入手機號碼\"]")); if (buttonList.size() != 0 ) { return true; } else { return false; } } }

** * 根據不同的頁面進行不同的處理 */ public class CompanyInfoPageHandle { public static void handleDifferentPage(WebDriver driver){ try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } String pageStatus = CompanyInfoPageClassification.PageClassificationMain(driver); switch (pageStatus){ case "驗證碼": //1、如果是驗證碼頁面那么需要在這里進行處理,例如手動輸入驗證碼。如果驗證碼比較簡單可以使用字符識別的方法 System.out.println("驗證碼頁面"); //2、登錄完了之后再判斷是什么頁面,然后再對當前頁面進行處理 handleDifferentPage(driver); break; case "登錄": //1、如果是登錄頁面那就進行登錄 login(driver, "用戶名","密碼"); //2、登錄完了之后再判斷是什么頁面,然后再對當前頁面進行處理 handleDifferentPage(driver); break; case "404": break; } } private static void login(WebDriver driver, String userName, String password){ WebElement phoneElement = driver.findElement(By.cssSelector("input[placeholder=\"請輸入手機號碼\"]")); phoneElement.sendKeys(userName); WebElement passwordElement = driver.findElement(By.cssSelector("input[placeholder=\"請輸入密碼\"]")); passwordElement.sendKeys(password); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } List<WebElement> elements2 = driver.findElements(By.cssSelector("div a.btn")); WebElement login = elements2.get(0); login.click(); } }
3. github地址並總結經驗
經驗總結:
1.在寫代碼時,會遇到一些錯誤,例如 li 標簽下有 a 標簽,如下面代碼。如果只定位到 li 標簽再調用 click() 方法會出現異常,還是要定位到 a 標簽,再進行點擊
<li><a href="/example" data-marko="{"onclick":"handleClickDebounce s0-9-20 false 0"}">2</a></li>
2.使用selenium + ChromeDriver進行爬蟲並不能完全自動化,對於當前這個網站來說,當點擊頻率過高時需要你登錄。因此我直接一開始就登錄賬號。登錄之后點擊頻率再上來之后,就需要輸入驗證碼,對於這種情況如果是一般的數字的驗證碼還可以用字符識別的技術。但是這個網站的驗證碼很難機器識別。
3.使用selenium + ChromeDriver進行爬蟲其實是一個很雞肋的東西,別人想要反扒你,其實很簡單。
第一步:游客模式的時候對每個ip的請求頻率做判斷,只要超過某個頻率那么需要你登錄
第二步:第一步完成后你就有個賬號,直接通過賬號的請求頻率或頻次做判斷,如果超過某個頻率或頻次那么需要你人機驗證。目前的驗證碼都非常惡心,不再像以前那種字符的
4.當然使用selenium + ChromeDriver還是能夠爬取一些數據,但是具體過程還需要人工干預,在碰到驗證碼的時候要暫停線程,然后輸入驗證碼。不過 selenium 本身的主要目的也不是爬蟲,而是做網頁的自動化測試。具體想要爬取數據還是需要使用代理,直接發送接口請求恐怕才能獲得持久穩定的數據。