Tomcat

Tomcat 是怎樣處理搜索引擎爬蟲請求的?

Google+ Pinterest LinkedIn Tumblr

Tomcat 是怎樣處理搜索引擎爬蟲請求的?

每個置身於網際網路中的站點,都需要搜索引擎的收錄,以及在適時在結果中的展現,從而將資訊提供給使用者、讀者。

而搜索引擎如何才能收錄我們的站點呢?

這就涉及到一個「搜索引擎的爬蟲」 取站點內容的過程。只有被搜索引擎爬過並收錄的內容纔有機會在特定query命中之後在結果中展現。

這些搜索引擎爬內容的工具,又被稱為爬蟲、Sprider,Web crawler 等等。我們一方面歡迎其訪問站點以便收錄內容,一方面又因其對於正常服務的影響頭疼。畢竟 Spider 也是要佔用伺服器資源的, Spider 太多太頻繁的資源佔用,正常使用者請求處理就會受到影響。所以一些站點乾脆直接為搜索引擎提供了單獨的服務供其訪問,其他正常的使用者請求走另外的伺服器。

說到這裏需要提一下,對於是否是 Spider 的請求識別,是通過HTTP 請求頭中的User-Agent 欄位來判斷的,每個搜索引擎有自己的獨立標識。而且通過這些內容,管理員也可以在訪問日誌中瞭解搜索引擎爬過哪些內容。

此外,在對搜索引擎的「爬取宣告檔案」robots.txt中,也會有類似的User-agent 描述。比如下面是taobao 的robots.txt描述

User-agent:  Baiduspider
Allow:  /article
Allow:  /oshtml
Disallow:  /product/
Disallow:  /

User-Agent:  Googlebot
Allow:  /article
Allow:  /oshtml
Allow:  /product
Allow:  /spu
Allow:  /dianpu
Allow:  /oversea
Allow:  /list
Disallow:  /

User-agent:  Bingbot
Allow:  /article
Allow:  /oshtml
Allow:  /product
Allow:  /spu
Allow:  /dianpu
Allow:  /oversea
Allow:  /list
Disallow:  /

User-Agent:  360Spider
Allow:  /article
Allow:  /oshtml
Disallow:  /

User-Agent:  Yisouspider
Allow:  /article
Allow:  /oshtml
Disallow:  /

User-Agent:  Sogouspider
Allow:  /article
Allow:  /oshtml
Allow:  /product
Disallow:  /

User-Agent:  Yahoo!  Slurp
Allow:  /product
Allow:  /spu
Allow:  /dianpu
Allow:  /oversea
Allow:  /list
Disallow:  /

我們再來看 Tomcat對於搜索引擎的請求做了什麼特殊處理呢?

對於請求涉及到 Session,我們知道通過 Session,我們在服務端得以識別一個具體的使用者。那 Spider 的大量請求到達後,如果訪問頻繁同時請求量大時,就需要建立 巨大量 的 Session,需要佔用和消耗很多記憶體,這無形中佔用了正常使用者處理的資源。 

為此, Tomcat 提供了一個 「 Valve 」,用於對 Spider 的請求做一些處理。

首先識別 Spider 請求,對於 Spider 請求,使其使用相同的 SessionId繼續後面的請求流程,從而避免建立大量的 Session 資料。

這裏需要注意,即使Spider顯式的傳了一個 sessionId過來,也會棄用,而是根據client Ip 來進行判斷,即對於 相同的 Spider 只提供一個Session。

我們來看程式碼:

// If the incoming request has a valid session ID, no action is required
if (request.getSession(false) == null) {

// Is this a crawler - check the UA headers
Enumeration<String> uaHeaders = request.getHeaders("user-agent");
String uaHeader = null;
if (uaHeaders.hasMoreElements()) {
uaHeader = uaHeaders.nextElement();
}

// If more than one UA header - assume not a bot
if (uaHeader != null && !uaHeaders.hasMoreElements()) {
if (uaPattern.matcher(uaHeader).matches()) {
isBot = true;
if (log.isDebugEnabled()) {
log.debug(request.hashCode() +
": Bot found. UserAgent=" + uaHeader);
}
}
}

// If this is a bot, is the session ID known?
if (isBot) {
clientIp = request.getRemoteAddr();
sessionId = clientIpSessionId.get(clientIp);
if (sessionId != null) {
request.setRequestedSessionId(sessionId); // 重用session
}
}
}

getNext().invoke(request, response);

if (isBot) {
if (sessionId == null) {
// Has bot just created a session, if so make a note of it
HttpSession s = request.getSession(false);
if (s != null) {
clientIpSessionId.put(clientIp, s.getId()); //針對Spider生成session
sessionIdClientIp.put(s.getId(), clientIp);
// #valueUnbound() will be called on session expiration
s.setAttribute(this.getClass().getName(), this);
s.setMaxInactiveInterval(sessionInactiveInterval);

if (log.isDebugEnabled()) {
log.debug(request.hashCode() +
": New bot session. SessionID=" + s.getId());
}
}
} else {
if (log.isDebugEnabled()) {
log.debug(request.hashCode() +
": Bot session accessed. SessionID=" + sessionId);
}
}
}

判斷Spider 是通過正則

private String crawlerUserAgents =
    ".*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.*";

// 初始化Valve的時候進行compile

uaPattern = Pattern.compile(crawlerUserAgents);

這樣當 Spider 到達的時候就能通過 User-agent識別出來並進行特別處理從而減小受其影響。

這個 Valve的名字是:「 CrawlerSessionManagerValve 」,好名字一眼就能看出來作用。

其他還有問題麼?我們看看,通過ClientIp來判斷進行Session共用。

最近 Tomcat 做了個bug fix,原因是這種通過ClientIp的判斷方式,當 Valve 配置在Engine下層,給多個Host 共用時,只能有一個Host生效。 fix之後,對於請求除ClientIp外,還有Host和 Context的限制,這些元素共同組成了 client標識,就能更大程度上共用Session。

修改內容如下:

Tomcat 是怎樣處理搜索引擎爬蟲請求的?

關於Session管理等相關的內容,可以看下我之前的幾篇文章:

對於過期的session,Tomcat做了什麼?

深入Tomcat原始碼分析Session到底是個啥!

Tomcat的Session持久化策略

關於 Valve 的功能及使用,可以看這幾篇文章:

閥門(Valve)常開啟,快發請求過來 | Tomcat的AccessLogValve介紹

如何避免Manager應用被人利用

總結下, 該Valve 通過標識識別出 Spider 請求後,給其分配一個固定的Session,從而避免大量的Session建立導致我資源佔用。

預設該Valve未開啟,需要在 server.xml中 增加配置開啟。另外我們看上面提供的 正則 pattern,和taobao 的robots.txt對比下,你會出現並沒有包含國內的這些搜索引擎的處理,這個時候怎麼辦呢?

在配置的時候傳一下進來就OK啦,這是個public 的屬性

public void setCrawlerUserAgents(String crawlerUserAgents) {
this.crawlerUserAgents = crawlerUserAgents;
if (crawlerUserAgents == null || crawlerUserAgents.length() == 0) {
uaPattern = null;
} else {
uaPattern = Pattern.compile(crawlerUserAgents);
}
}

相關閱讀:

深度揭祕亂碼問題背後的原因及解決方式

怎樣閱讀原始碼?

讀原始碼時,我們到底在讀什麼?

Tomcat程序自動退出問題

Tomcat與記憶體洩露處理

關注『  Tomcat那些事兒    ,發現更多精彩文章!瞭解各種常見問題背後的原理與答案。深入原始碼,分析細節,內容原創,歡迎關注。

Tomcat 是怎樣處理搜索引擎爬蟲請求的?

                        覺得不錯?轉發也是支援 ,謝謝

更多精彩內容:

一臺機器上安裝多個Tomcat 的原理(回覆001)

監控Tomcat中的各種資料 (回覆002)

啟動Tomcat的安全機制(回覆003)

亂碼問題的原理及解決方式(回覆007)

Tomcat 日誌工作原理及配置(回覆011)

web.xml 解析實現(回覆 012)

執行緒池的原理( 回覆 014)

Tomcat 的叢集搭建原理與實現 (回覆 015)

類載入器的原理 (回覆 016)

類找不到等問題 (回覆 017)

程式碼的熱替換實現(回覆 018)

Tomcat 程序自動退出問題 (回覆 019)

為什麼總是返回404? (回覆 020)

PS: 對於一些 Tomcat常見問 題,在公眾號的【 常見問題 】選單中,有需要的朋友歡迎關注檢視。

aa

Write A Comment