文章目錄
本文項目san-spider源碼地址
https://github.com/lufei222/san-spider.git
爬蟲概念
1、爬蟲基本概念
爬蟲的概念 :網絡爬蟲(又稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更經常的稱爲網頁追逐者),是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本。這是百度百科對爬蟲的定義,其實,說簡單點,爬蟲就是利用寫好的程序自動的提取網頁的信息。
2、爬蟲的分類
通用爬蟲:通用爬蟲是搜索引擎(Baidu、Google、Yahoo等)“抓取系統”的重要組成部分。主要目的是將互聯網上的網頁下載到本地,形成一個互聯網內容的鏡像備份。 簡單來講就是儘可能的;把互聯網上的所有的網頁下載下來,放到本地服務器裏形成備分,在對這些網頁做相關處理(提取關鍵字、去掉廣告),最後提供一個用戶檢索接口。
聚焦爬蟲:聚焦爬蟲是根據指定的需求抓取網絡上指定的數據。例如:獲取豆瓣上電影的名稱和影評,而不是獲取整張頁面中所有的數據值。
增量式爬蟲:增量式是用來檢測網站數據更新的情況,且可以將網站更新的數據進行爬取。
3、爬蟲的價值
抓取互聯網上的數據,爲我所用,有了大量的數據,就如同有了一個數據銀行一樣,下一步做的就是如何將這些爬取的數據產品化,商業化。
願景
開源的爬蟲框架已經很多了,有各種語言(比如:python、java)實現的,有單機的,還有大型分佈式的,多達上百種,詳情可見:
開源中國網絡爬蟲框架列表
33款可用來抓數據的開源爬蟲軟件工具
爬蟲項目經驗小結
github上有哪些優秀的java爬蟲項目
我們的要求也不高:
- 社區豐富,用戶量多,多人用的項目少踩坑。
- 文檔要全,上手快。
- 安裝和集成使用簡單。
- 代碼語法簡潔
- 爬蟲的主要功能要有,比如:支持請求頭部設置,支持代理,支持多線程,url自動去重複,html解析方便(至少要能支持css選擇器,xpath選擇器,正則表達式等常見的解析方式)
選定好一款爬蟲開源框架後,就要考慮自己的業務特點,設計自己的項目架構了,大多數用爬蟲的人,基本需求其實是類似的。
最終一般的爬蟲項目都是這樣的操作:
-
將目標網站的頁面儘可能快速的扒下來
-
然後解析出有用的內容
-
落地存儲到db、緩存
稍微成熟爬蟲開源框架基本上都已經實現了第一步 。
根據實際業務規則解析完了以後,如何落地、保持更新網站變更策略,都需要我們去考慮。
爬蟲框架選型
可以參考 開源網絡爬蟲框架應該怎麼選?
考慮選型的時候主要有以下參考項:
- 支持多線程?
- 爬蟲能用代理麼?
- 爬蟲會爬取重複數據麼?
- 爬蟲能爬取ajax生成的信息麼?
- 爬蟲怎麼抽取網頁信息
- 爬蟲怎麼保存網頁的信息
- 爬蟲速度如何?
- 報錯容易定位修改嗎?
上面說的爬蟲,基本可以分3類:
- 分佈式爬蟲:Nutch…
- JAVA單機爬蟲:Crawler4j、WebMagic、WebCollector、Gecco、Jsoup、Htmlunit
- 非JAVA單機爬蟲:Scrapy…
分佈式爬蟲
Nucth:
優點:分佈式抓取,存儲和索引,有hadoop支持,第三方插件豐富
缺點:使用上手難,用Nutch進行爬蟲的二次開發,爬蟲的編寫和調試所需的時間,往往是單機爬蟲所需的十倍時間不止。
單機爬蟲
對於單機爬蟲框架,日常開發中佔用時間多的地方就是網頁內容解析,所以首先要介紹下優秀的HTML網頁解析器 :Jsoup和Htmlunit和神器Selenium
- Jousp: 一款非常流行的Java的HTML解析器,主要用來對HTML解析。也可以進行Http請求網頁爬取源碼。
- Htmlunit:它不僅僅是一個HTML解析器。這是一個真正的“無GUI瀏覽器”和HTML單元測試工具。
- Selenium:Selenium是基於Web應用的驗收測試工具集合,直接運行在瀏覽器中,通過一系列命令來模擬用戶操作,Selenium可以將這些命令轉化成實際的HTTP請求在瀏覽器中運行 ,獲取到網頁信息和Cookie等信息
上面列舉的單機爬蟲中,Gecco基於註解方式實現,官方demo無法運行,體驗太差,首先排除不考慮。
對於其他幾個,功能都很豐富,且都在持續更新中。
name | Github Star | 文檔豐富度 | 使用項目數 | 網絡博文豐富度(10) |
---|---|---|---|---|
Crawler4j | 3.9k | 5 | 199 | 6 |
WebMagic | 9.1k | 非常齊全 | 586 | 7.5 |
WebCollector | 2.6k | 7 | 72 | 7.5 |
從以上幾個指標來看,都很優秀
基於我實際項目運行對比情,WebMagic文檔豐富上手快,demo項目多,所以當前日常使用WebMagic。
非Java單機爬蟲
主要說 Python 爬蟲,以Scrapy爲首,對比Java主要優勢在於
- Python的語法簡潔 ,入門簡單,節點解析簡潔高效,比如:Python 可以用 30 行代碼,完成 Java 50 行代碼乾的任務。Python 寫代碼的確快。
- 爬蟲用戶量大、社區活躍度大。
- Github基於Python實踐的項目基數巨大,對於大多數網站,基本有參考,拿來修改即用。
綜上對比:
分佈式爬蟲Nucth有點大材小用,開發效率也不高,暫時不打算考慮。
在日常Java項目中,我會首選WebMagic,而當需要花費大量時間精力去做爬蟲工作的時候,我會選擇Python的Scrapy。
爬蟲和反爬蟲
如何應對網站反爬蟲策略?如何高效地爬大量數據?
爬蟲突破封禁的6種常見方法
常見反爬蟲機制與應對方法
爬蟲與反爬蟲的博弈
爬蟲和反爬蟲都是一直在進步的,下面列舉一些常見的爬與反爬運用涉及的相關知識點
- 設置User-Agent
- 設置Cookie
- 訪問頻率限制
- 代理IP或者分佈式爬蟲:
- 構造合理的HTTP請求頭
網頁節點的解析方式
CSS選擇器 + Xpath + 正則表達式整理
xpath表達式
Jsoup、WebCollector、Htmlunit解析實例
Jsoup源碼
WebCollector源碼
接下來大篇幅主要介紹Webmagic,因爲先簡要介紹下其他解析器。
使HttpClient、Jsoup、Htmlunit爬取網頁實例代碼源碼:
LagouMulSpider.java
package demo;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.http.HttpEntity;
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.List;
import java.util.Random;
/**
* lagou多種不同方式實現的爬蟲
* 測試htmlunit、jsoup、httpclient直接爬取
*/
public class LagouMulSpider {
static Random random = new Random();
private static String LAGOU_URL = "https://www.lagou.com/zhaopin/ceo/1/?filterOption=3&sid=f1937baf1115438c9ea9aee62836a985";
public static void main(String[] args) throws IOException, InterruptedException {
//直接httpclient爬取lagou網頁,會提示存在惡意訪問行爲被攔截,
testHttpClient();
testJsoup();
testHtmlunitLagou();
testHtmlunitBaidu();
}
private static void testJsoup() throws IOException, InterruptedException {
System.out.println("************************testJsoup************************");
for(int i=0;i<2;i++) {
Document doc = Jsoup.connect(LAGOU_URL).get();
Elements newsHeadlines = doc.select(".pager_container");
System.out.println(newsHeadlines);
Thread.sleep(200);
}
}
private static void testHttpClient() {
try {
System.out.println("************************testHttpClient************************");
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(LAGOU_URL);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity, "utf-8");
response.close();
Jsoup.parse(content);
Document doc = Jsoup.parse(content);
Elements elements = doc.getElementsByTag("title");
System.out.println(elements);
}catch (Exception e){
System.out.println(e.getCause());
}
}
private static BrowserVersion getRandomBrowserVersion(){
int i = random.nextInt(5);
BrowserVersion browserVersion = BrowserVersion.getDefault();
switch (i){
case 1: browserVersion = BrowserVersion.CHROME ;break;
case 2: browserVersion = BrowserVersion.FIREFOX ;break;
case 3: browserVersion = BrowserVersion.FIREFOX_68 ;break;
case 4: browserVersion = BrowserVersion.BEST_SUPPORTED ;break;
case 5: browserVersion = BrowserVersion.INTERNET_EXPLORER ;break;
default: ;
}
return browserVersion;
}
/**
* 測試循環獲取lagou的頁面是否也是五次限制,還是真的能像瀏覽器一樣正常訪問.發現其實是一樣限流了,超過32秒才能繼續訪問
* @throws IOException
* @throws InterruptedException
*/
private static void testHtmlunitLagou() throws IOException, InterruptedException {
System.out.println("************************testHtmlunitLagou************************");
for(int i=0;i<2;i++){
//創建一個webclient
WebClient webClient = new WebClient(getRandomBrowserVersion());
//htmlunit 對css和javascript的支持不好,所以請關閉之
webClient.getOptions().setJavaScriptEnabled(false);
webClient.getOptions().setCssEnabled(false);
//獲取頁面
HtmlPage page = webClient.getPage(LAGOU_URL);
List<Object> byXPath = page.getByXPath("//div[@class='pager_container']//text()");
System.out.println(byXPath);
//關閉webclient
webClient.close();
}
}
private static void testHtmlunitBaidu() throws IOException {
System.out.println("************************testHtmlunitBaidu************************");
String str;
//創建一個webclient
WebClient webClient = new WebClient();
//htmlunit 對css和javascript的支持不好,所以請關閉之
webClient.getOptions().setJavaScriptEnabled(false);
webClient.getOptions().setCssEnabled(false);
//獲取頁面
HtmlPage page = webClient.getPage("http://www.baidu.com/");
//獲取頁面的TITLE
str = page.getTitleText();
System.out.println(str);
webClient.close();
}
}
WebMagic的介紹及使用
Java爬蟲框架WebMagic的介紹及使用(定時任務、代理)
官方文檔
Java爬蟲框架WebMagic入門
1、WebMagic框架簡介
PageProcessor、Scheduler、Downloader和Pipeline,對應爬蟲生命週期中的處理、管理、下載和持久化等功能,都是Spider中的屬性,爬蟲框架通過Spider啓動和管理。
WebMagic總體架構圖如下:
2、四大組件
- PageProcessor 負責解析頁面,抽取有用信息,以及發現新的鏈接。需要自己定義。
- Scheduler 負責管理待抓取的URL,以及一些去重的工作。一般無需自己定製Scheduler。
- Pipeline 負責抽取結果的處理,包括計算、持久化到文件、數據庫等。
- Downloader 負責從互聯網上下載頁面,以便後續處理。一般無需自己實現。
3、用於數據流轉的對象
Request 是對URL地址的一層封裝,一個Request對應一個URL地址。
Page 代表了從Downloader下載到的一個頁面——可能是HTML,也可能是JSON或者其他文本格式的內容。
ResultItems 相當於一個Map,它保存PageProcessor處理的結果,供Pipeline使用。
WebMagic+Selenium自動化登錄爬蟲實踐
WebMagic其他 demo
WebMagic實例 GiteeAutoLoginSpider.java
視頻展示效果如下
https://share.weiyun.com/liXqrw51
https://weibo.com/tv/v/J7HTMa0Zu?fid=1034:4518366212194347
package demo;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.pipeline.FilePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
/**
* gitee自動化登錄獲取私有項目
*/
public class GiteeAutoLoginSpider implements PageProcessor {
private static String GITEE_NAME = System.getenv("GITEE_NAME");
private static String GITEE_USERNAME = System.getenv("GITEE_USERNAME");
private static String GITEE_PASSWORD = System.getenv("GITEE_PASSWORD");
private static String GITEE_URL = "https://gitee.com/login";
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(10000);
// 用來存儲cookie信息
private Set<Cookie> cookies = new HashSet<>();
@Override
public Site getSite() {
// 將獲取到的cookie信息添加到webmagic中
for (Cookie cookie : cookies) {
site.addCookie(cookie.getName(), cookie.getValue());
}
return site;
}
/**
* 解析網頁節點具體業務邏輯
* @param page
*/
@Override
public void process(Page page) {
System.out.println("開始解析");
String tabName = page.getHtml().xpath("//a[@class='item f-bold']//allText()").get();
System.out.println(tabName);
List<String> projects = page.getHtml().xpath("//span[@class='project-title']//allText()").all();
List<String> privateProject = projects.stream().filter(x -> x.contains("san")).distinct().collect(Collectors.toList());
System.out.println(privateProject);
page.putField("gitee project ", privateProject);
}
/**
* 登錄獲取cookie的操作
*
* 使用selenium+chromedriver驅動完成自動登錄gitee獲取cookie的操作
* 對於大多數網站可以直接獲得cookie
* 對於大型的驗證比較多的網站,會比較麻煩,建議可以百度 或者 github參照其他項目的selenium自動登錄實現
* 在自動登錄實現不可行的時候,更快的方式是直接瀏覽器登錄手動複製cookie,以便後續登錄之後的操作繼續正常進行
*/
public void login() {
// 登陸
System.setProperty("webdriver.chrome.driver", "D:/chromedriver/chromedriver.exe"); // 註冊驅動
WebDriver driver = new ChromeDriver();
driver.get(GITEE_URL);// 打開網址
// 防止頁面未能及時加載出來而設置一段時間延遲
try {
Thread.sleep(1000);
// 設置用戶名密碼
driver.findElement(By.id("user_login")).sendKeys(GITEE_USERNAME); // 用戶名
driver.findElement(By.id("user_password")).sendKeys(GITEE_PASSWORD); // 密碼
// 模擬點擊
driver.findElement(By.name("commit")).click();
// 防止頁面未能及時加載出來而設置一段時間延遲
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 獲取cookie信息
cookies = driver.manage().getCookies();
System.out.println("cookie " + cookies);
driver.close();
}
public static void main(String[] args) {
String url = "https://gitee.com/"+GITEE_NAME+"/dashboard/projects?scope=private&&sort="; // 地址
GiteeAutoLoginSpider dome = new GiteeAutoLoginSpider();
// 登陸
dome.login();
Spider.create(dome)
.addUrl(url)
//輸出內容到控制檯
.addPipeline(new ConsolePipeline())
//輸出內容到文件
.addPipeline(new FilePipeline("D:\\webmagic\\gitee"))
.run();
}
}
結論和參考
經過項目的經驗時間,其實上面列舉的功能都很強大,如果只是Java項目當中由於一些需求需要使用,那麼其實Jsoup或者Htmlunit足矣,要有代理、多線程、去重、頭部設置、自動登錄等,則根據自己需要引入WebMagic或Selenium等,參照着Github上面的豐富的爬蟲項目肯定能完成自己的需求。
如果你需要投入大量時間精力在爬蟲上面的話,建議直接用Python的Scrapy,已有開源項目足矣讓你在爬蟲工作上游刃有餘。
本文項目san-spider源碼地址
https://github.com/lufei222/san-spider.git
參考
口罩地址Python
htmlunit 爬蟲案例
實例二 htmlunit
解決htmlunit的webclient對象在多線程環境下的共享問題
高級爬蟲進階:HtmlUnit+多線線程+消息隊列快速抓取大量信息數據
Java爬蟲,爬取京東、天貓、淘寶、阿里巴巴、蘇寧、國美、考拉電商數據
基於webmagic的爬蟲項目經驗小結
CSS選擇器 + Xpath + 正則表達式整理
在開源中國爬蟲分類的軟件
雪球網的爬蟲
今日頭條相關的httpunit
Nutch、heritrix、crawler4j優缺點
關於webmagic的說明文檔
基於Webmagic的Java爬蟲(四)爬取動態列表頁內容
基於webmagic的理財產品分頁
java爬蟲Gecco工具抓取新聞實例
爬蟲京東
java爬蟲事例
github上有哪些優秀的java爬蟲項目
https://www.zhihu.com/question/31427895
https://www.52pojie.cn/thread-1068214-1-1.html
使用WebMagic多線程爬取圖+httpClient多線程下載圖片
拉勾網爬取(WebMagic+Selenium+ChromeDriver)
https://blog.csdn.net/weixin_43719622/article/details/102784141
https://github.com/Yangtze-Innovation/Search-Job-Platfom/tree/CourageHe/2-WebMagic/4-WebMagicSelenimu
第一次用webmagic寫爬蟲
webmagic簡書
爬取動態頁面模擬登錄
WebMagic 實現爬蟲入門教程
爬取頁面需要登陸纔可爬取,這種怎麼解決
不能登錄的常見問題1
不能登錄的常見問題2
webmagic框架圖
WebMagic實現分佈式抓取以及斷點抓取,爬蟲主要運行時間消耗是請求網頁時的io阻塞,所以開啓多線程,讓不同請求的等待同時進行,可以大大提高爬蟲運行效率
多線程爬蟲圖
Gather Platform 聚集收集平臺
基於Crawler4j + jsoup實現蟲
selenium介紹
crawler4j簡介
htmlunit HtmlUnit的使用
webcollector簡介
Java開源爬蟲框架WebCollector爬取CSDN博客
爬取微信公衆號
Java開源爬蟲框架WebCollector爬取搜索引擎
爬蟲與反爬蟲