日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络爬虫初步:从一个入口链接开始不断抓取页面中的网址并入库

發(fā)布時間:2025/3/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络爬虫初步:从一个入口链接开始不断抓取页面中的网址并入库 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言:

? 在上一篇《網(wǎng)絡(luò)爬蟲初步:從訪問網(wǎng)頁到數(shù)據(jù)解析》中,我們討論了如何爬取網(wǎng)頁,對爬取的網(wǎng)頁進行解析,以及訪問被拒絕的網(wǎng)站。在這一篇博客中,我們可以來了解一下拿到解析的數(shù)據(jù)可以做的事件。在這篇博客中,我主要是說明要做的兩件事,一是入庫,二是遍歷拿到的鏈接繼續(xù)訪問。如此往復,這樣就構(gòu)成了一個網(wǎng)絡(luò)爬蟲的雛形。


筆者環(huán)境:

? 系統(tǒng):???? Windows 7
??????????? CentOS 6.5
? 運行環(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


效果圖:

? 這里只截取開始的一部分數(shù)據(jù)。這些數(shù)據(jù)我是保存在MySQL中的。

?

?

思路梳理:

? 前面說到,我們拿到數(shù)據(jù)要做兩件:數(shù)據(jù)保存與數(shù)據(jù)分析。

? 我們整個邏輯過程是這樣的:

??? 1.Java傳遞鏈接參數(shù)給Python;

??? 2.Python解析HTML返回必要信息給Java;

??? 3.Java拿到數(shù)據(jù)進行入庫;

??? 4.對解析出的有效鏈接進行繼續(xù)遍歷(這里是采用圖的廣度優(yōu)先遍歷)

??? 5.反復以上的4個步驟,直到?jīng)]有可繼續(xù)訪問的有效鏈接為止,這里是使用遞歸迭代。

? 關(guān)于數(shù)據(jù)保存,倒是沒有什么好說的。因為我是在Linux(CentOS)下運行程序的。所以,你的Linux中必須要有MySQL,另外,我是通過Java來進行數(shù)據(jù)庫操作的,所以這里你的系統(tǒng)中也有要Mysql的Java驅(qū)動包。

?

開發(fā)過程:

1.Python解析數(shù)據(jù)

get_html_response.py


# encoding=utf-8import HTMLParserimport utils as utilsclass ListWebParser(HTMLParser.HTMLParser):def __init__(self):HTMLParser.HTMLParser.__init__(self)self.tagAFlag = Falseself._name = Noneself._address = Noneself._info = []def handle_starttag(self, tag, attrs):if tag == 'a':for name, value in attrs:if name == 'href' and utils.isMatch(value, '^http'):self._info.append((self._name, self._address))self.tagAFlag = Trueself._address = valueself._name = None# print 'Address: ', valuedef handle_endtag(self, tag):if tag == 'a':self.tagAFlag = Falsedef handle_data(self, data):if self.tagAFlag:name = data.decode('utf-8')if self._name:self._name = str(self._name) + ' ' + nameelse:self._name = namedef getLinkList(self):return self._info
html_parser.py

# encoding=utf-8'''對Html文件進行解析 '''import sys reload(sys) sys.setdefaultencoding('utf8')from list_web_parser import ListWebParser import get_html_response as gethdef main(html):myp = ListWebParser()get_html = geth.get_html_response(html)myp.feed(get_html)link_list = myp.getLinkList()myp.close()for item in link_list:if item[0] and item[1]:print item[0], '$#$', item[1]if __name__ == "__main__":if not sys.argv or len(sys.argv) < 2:print 'You leak some arg.' # http://www.cnblogs.com/Stone-sqrt3/main(sys.argv[1])

2.Java入庫

對于Java中對數(shù)據(jù)庫的操作,也沒什么好說說明的。如果你寫地JDBC,那么這對于你而言將是小菜一碟。關(guān)鍵代碼如下:

public class DBServer {private String mUrl = DBModel.getMysqlUrl();private String mUser = DBModel.getMysqlUesr();private String mPassword = DBModel.getMysqlPassword();private String mDriver = DBModel.getMysqlDerver();private Connection mConn = null;private Statement mStatement = null;public DBServer() {initEvent();}private void initEvent() {mUrl = DBModel.getMysqlUrl();mUser = DBModel.getMysqlUesr();mPassword = DBModel.getMysqlPassword();mDriver = DBModel.getMysqlDerver();try {Class.forName(mDriver).newInstance();mConn = DriverManager.getConnection(mUrl, mUser, mPassword);mStatement = mConn.createStatement();} catch (Exception e) {e.printStackTrace();}}/*** 數(shù)據(jù)庫查詢* TODO* DBServer* @param sql* 查詢的sql語句*/public void select(String sql) {try {ResultSet rs = mStatement.executeQuery(sql);while (rs.next()) {String name = rs.getString("name");System.out.println(name);}rs.close();} catch (SQLException e) {e.printStackTrace();}}/*** 插入新數(shù)據(jù)* DBServer* @param sql* 插入的sql語句*/public int insert(String sql) {try {int raw = mStatement.executeUpdate(sql);return raw;} catch (SQLException e) {e.printStackTrace();return 0;}}/*** 某一個網(wǎng)址是否已經(jīng)存在* DBServer* @param sql* 查詢的sql語句*/public boolean isAddressExist(String sql) {try {ResultSet rs = mStatement.executeQuery(sql);if (rs.next()) {return true;}rs.close();} catch (SQLException e) {e.printStackTrace();}return false;}public void close() {try {if (mConn != null) {mConn.close();}if (mStatement != null) {mStatement.close();}} catch (Exception e) {e.printStackTrace();}} }

3.Java進行遞歸訪問鏈接

/*** 遍歷從某一節(jié)點開始的所有網(wǎng)絡(luò)鏈接* LinkSpider* @param startAddress* 開始的鏈接節(jié)點*/private static void ErgodicNetworkLink(String startAddress) {SpiderQueue queue = getAddressQueue(startAddress); // System.out.println(queue.toString());SpiderQueue auxiliaryQueue = null; // 記錄訪問某一個網(wǎng)頁中解析出的網(wǎng)址while (!queue.isQueueEmpty()) {WebInfoModel model = queue.poll();// TODO 判斷數(shù)據(jù)庫中是否已經(jīng)存在if (model == null || DBBLL.isWebInfoModelExist(model)) {continue;}// TODO 如果不存在就繼續(xù)訪問auxiliaryQueue = getAddressQueue(model.getAddres());System.out.println(auxiliaryQueue);// TODO 對已訪問的address進行入庫DBBLL.insert(model);if (auxiliaryQueue == null) {continue;}while (!auxiliaryQueue.isQueueEmpty()) {queue.offer(auxiliaryQueue.poll());}}}/*** 獲得某一鏈接下的所有合法鏈接* LinkSpider* @param htmlText* 網(wǎng)絡(luò)鏈接* @return*/private static SpiderQueue getAddressQueue(String htmlText) {if (htmlText == null) {return null;}SpiderQueue queue = PythonUtils.getAddressQueueByPython(htmlText);return queue;}

本程序的內(nèi)存及線程情況:

內(nèi)存:


線程:


爬取速度:



要點說明:

1.系統(tǒng)中的MySQL及MySQL包

? 你的Linux中必須要有MySQL,另外,我是通過Java來進行數(shù)據(jù)庫操作的,所以這里你的系統(tǒng)中也有要Mysql的Java驅(qū)動包。這一點在上面也有說明,不過這里還是要強調(diào)一下。如果你寫過JDBC的程序,那么這個驅(qū)動包,我想你應(yīng)該是有的,如果你沒寫過,那就去下一個吧。


2.需要一個輔助Queue

? 在上面的代碼中,我們可以看到我們有兩個SpiderQueue。一個是我們待訪問的隊列queue,保存我們將要訪問的鏈接列表;另一個是輔助隊列auxiliaryQueue,用于獲得從Python解析出來的數(shù)據(jù)。


3.使用圖的廣度優(yōu)先搜索算法進行鏈接爬取

? 這是從鏈接的相關(guān)性上考慮的。如果選擇深度優(yōu)先,那么隨著遍歷的深入,可能鏈接的相關(guān)性就會越來越小了。而廣度優(yōu)先搜索則不會這樣,因為我們都知道在同一個頁面中的鏈接總是會因為一些因素要展示在同一個頁面中,那么它們的相關(guān)性就會比較靠譜。


4.單線程與多線程

? 完成以上操作,如果你的程序正常運行。在前期是比較快的,可是到了穩(wěn)定期的時候就一般是1s鐘出一條數(shù)據(jù)。這個有點慢,我會在下一篇博客利用多線程來解決這個問題。


5.MySQL中添加一個叫cipher_address的字段

? 此字段用于address的加密生成(MD5 or SHA1)。下面舉個例子:

可能你有一個疑問,為什么要這個字段?如果你這樣思考了,那么對于你,是有益的。我們知道其實MySQL對一個很長的字符串進行select的時候,是相對來說比較慢的。這時,我們可以把這個address進行哈希一下,形成一個長度適中,又比較相近的字符串,這樣MySQL在比較時會容易一些(當然,你可以不使用這個字段)。


6.OOM異常

? 完全按照本文中的代碼和講解來進行編碼的話,會獲得一個OOM的異常(我的程序是跑了1天半的時時間)。如下:


數(shù)量大概在23145條左右


對于這一點在上面關(guān)于內(nèi)存和線程的展示圖中可以看到原因。

總結(jié)

以上是生活随笔為你收集整理的网络爬虫初步:从一个入口链接开始不断抓取页面中的网址并入库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美巨鞭大战丰满少妇 | 韩国黄色精品 | 久草中文在线观看 | 中文字幕永久在线播放 | 久久久精品一区二区 | 日本黄色美女视频 | 欧美色亚洲色 | 国产亚洲精品女人久久久久久 | 精品国产一区在线 | 蜜臀av一区二区三区有限公司 | 欧美精品黑人 | 69视频在线观看免费 | 日韩欧美一二三四区 | 玖玖玖国产精品 | 折磨小男生性器羞耻的故事 | 懂色av一区二区三区 | 天堂中文在线视频 | 国产精品98 | 婷婷午夜精品久久久久久性色av | 少妇无内裤下蹲露大唇视频 | 欧美 日韩 国产 成人 在线观看 | 1级黄色大片 | 国产欧美高清 | 手机在线看片日韩 | 久久精品一区二区三区四区 | 蜜桃av在线 | 日韩精品啪啪 | 日本加勒比一区二区 | 高潮毛片 | 黄色大片av | 精品国产一二三区 | 国产电影一区二区三区 | 特级做a爱片免费69 少妇第一次交换又紧又爽 亚洲大胆人体 | 蜜臀久久精品久久久久 | 国产无遮挡免费观看视频网站 | 自拍偷拍亚洲欧洲 | 修仙淫交(高h)h文 | 亚洲欧美激情在线观看 | 国产亚洲成av人片在线观看桃 | 国产又粗又猛又爽又黄的视频在线观看动漫 | 长篇乱肉合集乱500小说日本 | 日本一道本在线 | 狠狠成人| 日本中文不卡 | 日韩在线视频免费看 | 欧美成人吸奶水做爰 | avtt亚洲天堂 | 第四色激情| 狠狠入 | 精品影视一区二区 | 探花系列在线观看 | 日韩精品系列 | 女人脱下裤子让男人捅 | 蜜臀在线视频 | 国产伦精品一区 | 欧美三级午夜理伦三级中视频 | 国产高清在线一区 | 国产哺乳奶水91在线播放 | 激情视频激情小说 | 欧美a网 | 久爱视频在线 | 神马影院一区二区三区 | www.亚洲成人 | 神马久久春色 | 日日夜夜中文字幕 | 日韩视频在线免费播放 | 一级在线免费视频 | 日批视频免费在线观看 | 综合精品国产 | 人成网站在线观看 | 操久久久 | 先锋影音av资源在线观看 | 日本黄色xxxxx | 熟妇一区二区三区 | 欧美在线视频精品 | 亚洲色偷精品一区二区三区 | 一区在线观看视频 | 欧美激情一区二区三区免费观看 | 日韩综合区 | 亚洲精品一区二三区 | 国产chinese男男gaygay视频 | 欧美日韩一区二区在线视频 | 国产成人a∨ | 激情免费av | 制服丝袜国产精品 | 老师张开让我了一夜av | 在线视频h | 河北彩花中文字幕 | 在线观看日韩 | 久久精品99久久久久久久久 | 红桃视频网站 | 都市激情综合 | 国产做a视频 | 天堂中文视频 | 欧美精品卡一卡二 | 艳母日本动漫在线观看 | 91美女视频在线观看 | 一区二区中文字幕 | 伊伊总综合网 |