java爬蟲進階 —— ip池使用,iframe嵌套,異步訪問破解


寫之前稍微說一下我對爬與反爬關系的理解

一、什么是爬蟲
      爬蟲英文是splider,也就是蜘蛛的意思,web網絡爬蟲系統的功能是下載網頁數據,進行所需數據的采集。主體也就是根據開始的超鏈接,下載解析目標頁面,這時有兩件事,一是把相關超鏈接繼續往容器內添加,二是解析頁面目標數據,不斷循環,直到沒有url解析為止。舉個栗子:我現在要爬取蘇寧手機價格數據,爬取思路就是拿到第一頁的url作為蜘蛛網的中心點開始,爬取當頁的手機詳情頁面的價格信息以及下一頁的url並添加進容器,這樣循環往復只要存放url容器里有就會一直往下機械執行,直到尾頁沒有下一頁,這就是個擴散的過程。

 

 

二、什么是反爬蟲以及為什么要反
    反爬蟲就是根據請求的一定的訪問特征進行特殊處理,比如封Ip,彈驗證碼,返回不對應信息等等。

    至於反爬的原因大概有幾點

    1、爬蟲占總PV值高,就相當於一大群僵屍用戶在訪問你的網站,如果不管制,平白浪費服務器資源

    2、某些則是出於商業競爭問題必須反爬,不讓自己的商業信息被對手批量獲取。之前看到一個例子很貼切,兩個to B公司對外售賣商品,而一家寫了一個自動爬取對手網站商品價格並於己方商品價格對比,保持低於一定價格進行動態浮動的腳本,顧客在買之前肯定會對同行業價格進行了解,於是結果你們都懂,對方很快發現這邊的公司動的手腳,於是一場哄哄烈烈爬與反爬的較量開始了

    3、還有就是一些無人認領的爬蟲,可能用的人都忘了它的存在,一直在辛勤的爬

 

三 、常見的一些反爬手段
    1、根據ip訪問頻率以及數量上限封鎖ip,那個用戶會一秒訪問頁面幾十次或者連續幾小時每隔半秒訪問一次,動作很明顯,封就完事了。

2、還有就是加載頁面時動態獲取,而不是靜態數據了。舉個栗子,某東的價格信息是動態加載

    3、還有就是主體頁面是異步加載嵌套在iframe里面的,並且 src="about:blank" ,這個正常下載下來的頁面是沒有內容的

    4、故意挖坑,在頁面做一些隱藏鏈接,如果被訪問明顯是爬進去的爬蟲,接下來就是一頓封

    5、后台對方問進行統計,對userAgent進行閾值判斷,這個據說容易誤傷

    6、還有就是在頁面展示上進行做手腳,有的價格信息用圖片展示,去哪兒網

    7、Cookie反扒,推薦鏈接,有一篇不錯的介紹傳送門

 

四、對前三種進行破解
    1.設立ip池循環進行循環訪問

     首先我們從西刺等代理網站抓取一些免費的ip,其次進行無效ip過濾,這一步看情況吧,我個人實踐是西刺網上得ip時而訪問得通時而無效,所以我就去掉過濾得步驟,再就是用這些代理ip進行實際訪問。

public class CsdnReadCount implements PageProcessor {


// IP地址代理庫Map
private static Map<String, Integer> IPProxyRepository = new HashMap<>();
private static List<String> keysArray = new ArrayList<>();
private static int index;

private Site site = Site
.me()
.setDomain("http://www.xicidaili.com/")
.setSleepTime(3000).setUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");

//按照順序獲取一個ip
public static HttpHost getRandomProxy() {

// 隨機獲取host:port,並構建代理對象
String host = keysArray.get(index);
if(index<keysArray.size()-1) {
index+=1;
}else {
index = 0;
}

int port = IPProxyRepository.get(host);
HttpHost proxy = new HttpHost(host, port); // 設置http代理
return proxy;
}

//抓取西刺網前兩頁上代理IP,因為不穩定,所以不做過濾
public void process(Page page) {

Html html = page.getHtml();
List<String> hosts = html.xpath("//div[@id='body']/table/tbody/tr[@class='odd']/td[2]").replace("<td>","").replace("</td>","").all();
List<String> ports = html.xpath("//div[@id='body']/table/tbody/tr[@class='odd']/td[3]").replace("<td>","").replace("</td>","").all();

keysArray.addAll(hosts);
for (int i=0;i<hosts.size();i++){
IPProxyRepository.put(hosts.get(i),Integer.valueOf(ports.get(i)));
}
}

public Site getSite() {
return site;
}

//請求頁面,返回頁面html代碼
public static String getHttpContent(String url)throws IOException {

HttpHost proxy = getRandomProxy();
CloseableHttpClient httpClient = HttpClients.custom().setProxy(proxy).build(); // 創建httpclient對象


HttpGet request = new HttpGet(url); // 構建htttp get請求
request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();

request.setConfig(requestConfig);
String host = null;
Integer port = null;
if (proxy != null) {
host = proxy.getHostName();
port = proxy.getPort();
}

request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

try {

CloseableHttpResponse response = httpClient.execute(request);
String result = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println("ip"+host+"連接成功"+index);
System.out.println(result);
System.out.println(new Date());
}catch (Exception c){
System.out.println("ip"+host+"連接失敗···");
System.out.println("index:"+index);
System.out.println(new Date());
}

return null;
}

public static void main(String[] args) throws InterruptedException,IOException{

CsdnReadCount csdnReadCount = new CsdnReadCount();
Spider spider = Spider.create(csdnReadCount);
spider.addUrl("http://www.xicidaili.com/nn/1");
spider.addUrl("http://www.xicidaili.com/nn/2");

spider.run();

getHttpContent("https://blog.csdn.net/caihaijiang/article/list/1");

}
}

    2.異步嵌套iframe的破解

    這里用到了selenium需要引入依賴

    准備: 下載谷歌驅動(谷歌驅動的版本一定要對應谷歌瀏覽器得版本,否則會報錯)驅動下載傳送門

                引入所需依賴  :  

<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.3.1</version>
</dependency>
package sample;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.ArrayList;
import java.util.List;

public class SeleniumCloudMusic {

public static void main(String[] args) {


String key="webdriver.chrome.driver";
//谷歌驅動在你本地位置
String value="C:/Users/win 10/Desktop/暫存/chromedriver.exe";
System.setProperty(key,value);

WebDriver driver = new ChromeDriver();
driver.get("http://music.163.com/#");

WebElement iframe = driver.findElement(By.className("g-iframe"));
driver.switchTo().frame(iframe);

List<WebElement> elements = driver.findElements(By.xpath("//div[@class='u-cover u-cover-1']"));
List<String> playLists = new ArrayList<String>();

for (WebElement webElement:elements){
webElement.findElement(By.tagName("div"));
WebElement node = webElement.findElement(By.tagName("a"));
String url = node.getAttribute("href");

System.out.println(url);
playLists.add(url);

}

for (String str:playLists){


driver.get(str);
WebElement ifra = driver.findElement(By.className("g-iframe"));
driver.switchTo().frame(ifra);

WebElement subject = driver.findElement(By.tagName("h2"));

System.out.println(subject.getText());
}
}
}
3.動態加載破解

      此處依舊是某些網站加載數據通過ajax異步加載,你直接爬是沒有信息的,所以需要爬取頁面數據過程中單獨生成請求獲取價格數據

package sample;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import org.json.JSONArray;
import org.json.JSONObject;

public class JDPriceSplider implements PageProcessor {
private Site site = Site
.me()
.setDomain("https://item.jd.com")
.setSleepTime(3000);

public void process(Page page) {

String url = page.getUrl().get();
String id = url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
//拼接獲取價格的url
String priceUrl = "https://p.3.cn/prices/mgets?pduid=1504781656858214892980&skuIds=J_" + id;

//獲取價格json信息
String priceJson = getHttpContent(priceUrl);
if (priceJson != null) {
// 解析json [{"op":"4899.00","m":"9999.00","id":"J_3133843","p":"4799.00"}] 將該json字符串封裝成json對象
if (priceJson.contains("error")) { // 返回{"error":"pdos_captcha"},說明價格url已經不可用,更換pduid再做解析
} else {
JSONArray priceJsonArray = new JSONArray(priceJson);
JSONObject priceJsonObj = priceJsonArray.getJSONObject(0);
String priceStr = priceJsonObj.getString("p").trim();
Float price = Float.valueOf(priceStr);


System.out.println(price);
}
}
}

//相當於頁面進行ajax調用,單獨獲取價格
public static String getHttpContent(String url) {

CloseableHttpClient httpClient = HttpClients.custom().build(); // 創建httpclient對象

HttpGet request = new HttpGet(url); // 構建htttp get請求
request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");


RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();
request.setConfig(requestConfig);

try {
CloseableHttpResponse response = httpClient.execute(request);

return EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

public Site getSite() {
return site;
}

public static void main(String[] args) {

//訪問手機詳情頁面
Spider spider = Spider.create(new JDPriceSplider());
spider.addUrl("https://item.jd.com/6946605.html");
spider.run();
}
}
---------------------
作者:紫荊王朝
來源:CSDN
原文:https://blog.csdn.net/wu18296184782/article/details/80269274
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM