网络爬虫初步:从访问网页到数据解析
前言:
? 網(wǎng)絡(luò)爬蟲這個(gè)東西看上去還是很神奇的。不過,如果你細(xì)想,或是有所研究就知道,其實(shí)爬蟲并不那么高深。高深的是在我們的數(shù)據(jù)量很大的時(shí)候,就是當(dāng)我們網(wǎng)絡(luò)“圖”的回環(huán)越來越多的時(shí)候,應(yīng)該怎么去解決它。
? 本篇文章在這里只是起一個(gè)拋磚引玉的作用。本文主要是講解了如何使用Java/Python訪問網(wǎng)頁并獲得網(wǎng)頁代碼、Python模仿瀏覽器進(jìn)行訪問網(wǎng)頁和使用Python進(jìn)行數(shù)據(jù)解析。希望我們以本文開始,一步一步解開網(wǎng)絡(luò)蜘蛛神秘的一面。
參考:
1.《自己動(dòng)手寫網(wǎng)絡(luò)爬蟲》
2.用python 寫爬蟲,去爬csdn的內(nèi)容,完美解決 403 Forbidden
運(yùn)行效果圖:
??
? 內(nèi)容有點(diǎn)多,我只選取了一部分進(jìn)行展示。
筆者環(huán)境:
? 系統(tǒng): ? ? Windows 7
? ? ? ? ? ? CentOS 6.5
? 運(yùn)行環(huán)境: ?JDK 1.7
? ? ? ? ? ? Python 2.6.6
? IDE: ? ? ?Eclipse?Release 4.2.0
? ? ? ? ? ? PyCharm 4.5.1
? 數(shù)據(jù)庫: ? ?MySQL?Ver 14.14 Distrib 5.1.73
開發(fā)過程:
1.使用Java抓取頁面
? 對于頁面抓取我們采用Java來實(shí)現(xiàn),當(dāng)然你可以使用其他的語言來開發(fā)。不過
? 下面以“博客園”的首頁為例,展示一下使用Java進(jìn)行網(wǎng)頁頁面抓取的過程:
public class RetrivePageSimple {private static HttpClient httpClient = new HttpClient();// 設(shè)置代理服務(wù)器static {httpClient.getHostConfiguration().setProxy("58.220.2.132", 80);}public static boolean downloadPage(String path) throws HttpException,IOException {PostMethod postMethod = new PostMethod(path);// 執(zhí)行,返回狀態(tài)碼int statusCode = httpClient.executeMethod(postMethod);System.out.println(statusCode);// 針對狀態(tài)碼進(jìn)行處理 (簡單起見,只處理返回值為200的狀態(tài)碼)if (statusCode == HttpStatus.SC_OK) {String a = postMethod.getResponseBodyAsString();System.out.println(a);return true;}return false;}public static void main(String[] args) {try {RetrivePageSimple.downloadPage("http://www.cnblogs.com/");} catch (HttpException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} } ?
? 結(jié)果信息在這里就不再展示,太多了。。。- -!
2.使用Python抓取頁面
? 可能你會(huì)問我,為什么上面寫了使用Java版的頁面抓取,這里又要寫一個(gè)Python?這是有必要的。因?yàn)楣P者在開發(fā)這個(gè)demo之前沒有考慮一個(gè)問題。我們使用Java抓取了一個(gè)網(wǎng)頁給Python的時(shí)候,這個(gè)網(wǎng)頁字符串過長,無法作為參數(shù)傳遞。可能你會(huì)覺得保存文件是一個(gè)不錯(cuò)的選擇,那html文件太多又要怎么辦呢?是的,這里我們不得不舍棄這種讓人心累的做法。
? 考慮到是因?yàn)閰?shù)長度的限制,這里我們在Java端只給出頁面地址,抓取網(wǎng)頁使用Python來進(jìn)行。
? 按照最簡單的方式,通常我們會(huì)像這樣來使用Python網(wǎng)頁:
import urllib2 result = urllib2.urlopen('http://blog.csdn.net/mobile/index.html') html = result.read()print html
? 可是,筆者代碼中使用的是CSDN的博客頻道的url,CSDN對來自爬蟲的訪問進(jìn)行一層過濾,如下我們會(huì)得到如下錯(cuò)誤信息:
??
? 403,我被拒絕了。
3.使用模仿瀏覽器登錄網(wǎng)站
? 前面說到我們?nèi)ピL問帶有保護(hù)措施的網(wǎng)頁時(shí),會(huì)被拒絕。不過我們可以嘗試使用自己的瀏覽器來訪問它,是可以訪問的。
? 也就是說如果我們可以在Python中去模仿自己是瀏覽器就可以對這個(gè)網(wǎng)頁進(jìn)行訪問了。下面是Python模仿瀏覽器的代碼:
import random import socket import urllib2 import cookielibERROR = {'0':'Can not open the url,checck you net','1':'Creat download dir error','2':'The image links is empty','3':'Download faild','4':'Build soup error,the html is empty','5':'Can not save the image to your disk',}class BrowserBase(object):def __init__(self):socket.setdefaulttimeout(20)self._content = Nonedef speak(self, name, content):print '[%s]%s' % (name, content)def open_url(self, url):"""打開網(wǎng)頁"""cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar())self.opener = urllib2.build_opener(cookie_support,urllib2.HTTPHandler)urllib2.install_opener(self.opener)user_agents = ['Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11','Opera/9.25 (Windows NT 5.1; U; en)','Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)','Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)','Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12','Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9',"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7","Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 ",]agent = random.choice(user_agents)self.opener.addheaders = [("User-agent", agent), ("Accept", "*/*"), ('Referer', 'http://www.google.com')]try:res = self.opener.open(url)self._content = res.read()# print self._contentexcept Exception, e:self.speak(str(e)+url)raise Exceptionelse:return resdef get_html_content(self):return self._contentdef get_html_response(html):spider = BrowserBase()spider.open_url(html)return spider.get_html_content()
? 上面的代碼是可以正常得到返回值的。如下就來看看對返回的結(jié)果的解析過程吧。
4.數(shù)據(jù)解析
? 使用Python來進(jìn)行Html的解析工作,是異常的簡單:
import HTMLParserclass ListWebParser(HTMLParser.HTMLParser):def __init__(self):HTMLParser.HTMLParser.__init__(self)self.tagDIVFlag = Falseself.tagDIVAFlag = Falseself.tagH1Flag = Falseself.tagSecondHrefFlag = Falseself._name = Noneself._address = Nonedef handle_starttag(self, tag, attrs):if tag == 'div':for name, value in attrs:if name == 'class' and value == 'blog_list':self.tagDIVFlag = Trueif tag == 'h1':if self.tagDIVFlag:self.tagH1Flag = True# print 'h1->', self.tagH1Flagif tag == 'a':#if self.tagDIVAFlag:#print 'h1: ', self.tagH1Flagif self.tagH1Flag:for name, value in attrs:if name == 'target' and value == '_blank':self.tagDIVAFlag = Trueif name == 'href':if self.tagSecondHrefFlag:print '網(wǎng)址:', valueself._address = valueself.tagSecondHrefFlag = True# if name == 'href' and self.tagDIVAFlag:# print '網(wǎng)址:', value# self._address = valuedef handle_endtag(self, tag):if tag == 'div':self.tagDIVFlag = Falseif tag == 'h1':self.tagH1Flag = False# print 'false h1.'if tag == 'a':self.tagDIVAFlag = Falsedef handle_data(self, data):if self.tagDIVAFlag:print u"名稱:", data.decode("utf-8")
? 如果你說你在網(wǎng)上查找到的Html文件沒有這個(gè)麻煩。這個(gè)我是承認(rèn)的,因?yàn)檎G闆r下,我們解析一些簡單數(shù)據(jù)的確很簡單。上面代碼中的復(fù)雜邏輯是在處理篩選。
? 說到篩選,這里我用到一個(gè)小技巧(當(dāng)然,當(dāng)用的人多了,這就不再只是技巧。不過這種方法可以在以后的編碼過程中有所借鑒)。我們通過一些tag的特殊屬性(如:id, class等)來鎖定塊。當(dāng)我們開始塊的時(shí)候,我們相應(yīng)的標(biāo)志位會(huì)被打成True,當(dāng)我們退出塊的時(shí)候,我們相應(yīng)標(biāo)志位會(huì)被打成False。可能你覺得這太麻煩。其實(shí),你仔細(xì)想想就會(huì)知道,這是有道理的。
注意事項(xiàng):
1.在使用Java進(jìn)行頁面抓取的時(shí)候,我們用到了代理服務(wù)器。這個(gè)代理服務(wù)器的host和port是可以直接在網(wǎng)上查到免費(fèi)的。
2.你需要準(zhǔn)備以下jar包,并導(dǎo)入到你的Eclipse工程中:
3.修改MySQL的默認(rèn)編碼為UTF-8
? 這里因?yàn)闀?huì)有一些中文信息,所以我們需要對MySQL進(jìn)行編碼格式的轉(zhuǎn)換。
? 如果你是在Linux下編碼,那么你可以參考:http://blog.csdn.net/lemon_tree12138/article/details/46375637
總結(jié)
以上是生活随笔為你收集整理的网络爬虫初步:从访问网页到数据解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用MySQL Workbench远程管
- 下一篇: Java实现图的深度和广度优先遍历算法