在下抓數據也小有研究,現分享幾個自己研究出來的抓數據的技術,可能會有很多不足的地方,歡迎大家指正補充哈哈!
方法一:直接抓取網頁源碼
優點:速度快。
缺點:1,正由於速度快,易被服務器端檢測,可能會限制當前ip的抓取。對於這點,可以嘗試使用ip代碼解決。
2,如果你要抓取的數據,是在網頁加載完后,js修改了網頁元素,無法抓取。
3,遇到抓取一些大型網站,如果需要抓取如登錄后的頁面,可能需要破解服務器端帳號加密算法以及各種加密算法,及其考驗技術性。
適用場景:網頁完全靜態化,並且你要抓取的數據在網頁首次加載完成就加載出來了。涉及登錄或者權限操作的類似頁面未做任何帳號加密或只做簡單加密的。
當然,如果該網頁你抓取的數據,是通過接口獲得的json,那么,你就更幸福的,直接抓取json頁面即可。
對於有登錄的頁面,我們如何拿到他的登錄頁之后的源碼呢?
首先我要介紹一下,對於session保存帳號信息的情況下,服務器是如何確定該用戶身份的。
首先,用戶登錄成功后,服務器端會將用戶的當前會話信息保存到session中,每一個session有一個唯一標志sessionId。則用戶訪問這個頁面,session被創建后,就會接收到服務器端傳回的sessionId,並將其保存到cookie中,因此,我們可以用chrome瀏覽器打開檢查項,查看當前頁面的jsessionId。下次用戶訪問需要登錄的頁面時,用戶發送的請求頭會附上這個sessionId,服務器端通過這個sessionId就可以確定用戶的身份。
這里,我搭建了一個簡單的jsp登錄頁面,登錄后的帳號信息保存在服務器端session中。
思路:1,登錄。2,登錄成功后獲得cookie。3,將cookie放到請求頭中,向登錄頁發送請求。
附上java版本的代碼及python
java版:
package craw;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
public class CrawTest {
//獲得網頁源代碼
private static String getHtml(String urlString,String charset,String cookie){
StringBuffer html = new StringBuffer();
try {
URL url = new URL(urlString);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setRequestProperty("Cookie", cookie);
BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream(),charset));
String str;
while((str=br.readLine())!=null){
html.append(str);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return html.toString();
}
//發送post請求,並返回請求后的cookie
private static String postGetCookie(String urlString,String params,String charset){
String cookies=null;
try {
URL url = new URL(urlString);
URLConnection urlConn = url.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
PrintWriter out = new PrintWriter(urlConn.getOutputStream());
out.print(params);
out.flush();
cookies = urlConn.getHeaderFields().get("Set-Cookie").get(0);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cookies;
}
public static void main(String[] args) {
String cookie = postGetCookie("http://localhost:8080/loginDemo/login",
"username=admin&password=123456","utf-8");
String html = getHtml("http://localhost:8080/loginDemo/index.jsp", "utf-8", cookie);
System.out.println(html);//這里我們就可能輸出登錄后的網頁源代碼了
}
}
python版:
#encoding:utf-8 import urllib import urllib2 data={'username':'admin','password':'123456'} data=urllib.urlencode(data) response = urllib2.urlopen('http://localhost:8080/loginDemo/login',data=data)//登錄 cookie = response.info()['set-cookie']//獲得登錄后的cookie jsessionId = cookie.split(';')[0].split('=')[-1]//從cookie獲得sessionId html = response.read() if html=='error': print('用戶名密碼錯誤!') elif html=='success': headers = {'Cookie':'JSESSIONID='+jsessionId}//請求頭 request =urllib2.Request('http://localhost:8080/loginDemo/index.jsp',headers=headers) html = urllib2.urlopen(request).read() print(html)//輸出登錄后的頁面源碼
我們可以很明顯看出python的優勢,會比java少寫至少一半的代碼量,當然這即是java的優點,也是java的缺點,優點就是更加靈活,程序員可以更好的控制底層代碼的實現,缺點就是不易上手,對技術要求過高,因此,如果你是一名數據抓取新人,個人極力推薦你學習python。
方法二:模擬瀏覽器操作
優點:1,和用戶操作相類似,不易被服務器端檢測。
2,對於登錄的網站,即使是經過了N層加密的,無需考慮其加密算法。
3,可隨時獲得當前頁面各元素最新狀態。
缺點:1,速度稍慢。
這里介紹幾個不錯的模擬瀏覽器操作的類庫:
C# webbrower控件:
如果你研究過c# winform,相信你絕對不會對webbrower這個控件陌生,他就是一個瀏覽器,內部驅動其實也是ie的驅動。
他可以以dom方式隨時解析當前的document(網頁文檔對象),不僅可以拿到相關Element對象,還可以對element對象進行修改,乃至調用方法,如onclick方法,onsubmit等等,也可以直接調用頁面js方法。
C#對webbrower操作代碼:
webBrowser1.Navigate("https://localhost//index.html");//加載一個頁面 需要注意的是:不要直接執行以下代碼,因為網頁加載需要時間,建議以下代碼寫到webBrowser1_DocumentCompleted(加載完成)事件中: webBrowser1.Document.GetElementById("username").InnerText="admin";//在網頁中找到id為username的元素,設置其文本為admin webBrowser1.Document.GetElementById("password").InnerText = "123456";//在網頁中找到id為password的元素,設置其文本為123456 webBrowser1.Document.InvokeScript("loginEncrypt");//調用網頁js函數:loginEncrypt.
由於有些頁面ie可能不夠友好,或者如果ie版本過低,甚至是安全證書等問題,那么這個方案可能就pass掉了。
我們可以直接使用selenium庫來操作系統中真實瀏覽器,如chrome瀏覽器,selenuim支持多語言開發,以python調用selenium為例,selenium就是直接操作我們系統中的瀏覽器,但需要確保瀏覽器安裝對應的驅動。
然而,真正開發中,有時我們可能不希望看到這個瀏覽器界面,這里,我可以推薦大家一個后台瀏覽器,他直接在cmd中進行操作,沒有界面,那就是phantomjs。
這樣,我們使用python+selenium+phantomjs就可以模擬瀏覽器的操作,並且看不到界面,由於phantomjs沒有界面,所以他會比一般的瀏覽器要快很多。
這里網上有大量的資料,一時半會也講不請,這里就不做過多講解,大家可以看看:http://www.cnblogs.com/luxiaojun/p/6144748.html
三,Fidder script:
fidder是一款非常強大的數據抓取工具,他不僅可以抓取到當前系統中的http請求,他還可以提供安全證書,因此有時候,我們抓取過程中,如果遇到安全證書錯誤,我們不妨把fidder打開,讓他提供你一個證書,或許你就近成功近在咫尺。
令人更加強大的是fidder script,他可以在對抓取到了請求后,進行一系統操作,如將請求到的數據保存到硬盤中。或者在請求前,修改請求頭,可謂是抓取一利器,這樣,我們使用fidder配合上之前的各類方法,相信可以解決大多難題。並且他的語法和C like系列語法相似,類庫和c#大多相同,相信對C#熟悉的同學,上手fiddler script會很快。
fidder script:http://blog.csdn.net/crisschan/article/details/45602745
