動手寫爬蟲(3):爬取趕集網(wǎng)二手物品信息

掌握了BeatifulSoup的基本用法之后奠涌,爬取單個網(wǎng)頁實(shí)際上是比較簡單的:只需要使用requests庫中的get方法先向網(wǎng)頁發(fā)出請求职辨,用BeatifulSoup把網(wǎng)頁轉(zhuǎn)成soup抬闷,再對soup使用各種select方法铭污,即可得到所需的網(wǎng)頁元素葛作,再稍做整理腕柜,即可得到所需的結(jié)構(gòu)化內(nèi)容济似。

那么,如果要爬取一系列的網(wǎng)頁內(nèi)容呢盏缤?
這就需要對爬取過程做一下調(diào)度準(zhǔn)備了砰蠢,下面以趕集網(wǎng)二手物品信息為例,介紹一下10萬量級網(wǎng)頁的爬取過程唉铜。

0.爬取目標(biāo)

選擇一個地市的趕集全部二手物品類目作為爬取目標(biāo)台舱,爬取其下所有二手物品頁面、二手物品詳細(xì)信息潭流。

趕集二手物品類目.png

爬取目標(biāo).png

1.制定爬取過程策略

我們按照倒序來分析一下爬取過程
-最后一步:爬取最終的爬取頁面竞惋,也就是上面的圖二(爬取目標(biāo)),存儲所需信息
-倒數(shù)第二步:通過類目頁面獲取最后一步所需的最終頁面的鏈接
-倒數(shù)第三步:想辦法獲取類目頁面鏈接<-- 通過趕集首頁-二手欄目灰嫉,下方的二手物品類目拆宛,如上面圖一。

我們再把這個過程正過來讼撒,也就是正常在趕集上找到對應(yīng)物品信息的過程——爬取過程就是把這個找尋的過程重復(fù)再重復(fù)浑厚。

當(dāng)然,上述處理過程中根盒,需要將中間爬取的鏈接一步一步存儲下來钳幅、一步一步再提取出來使用,并規(guī)避重復(fù)炎滞。

**大規(guī)模爬取信息過程**.png

2.動手開始爬敢艰!

過程明確了,實(shí)現(xiàn)起來就不復(fù)雜了册赛。主要需要注意的是中間存url钠导、取url的過程:注意避免重復(fù)——爬過的留一個已爬記錄,爬前到這個記錄里檢查一下有沒有击奶,如果已爬辈双,那就跳過!

(1)第一部分代碼:獲取類目信息


import requests
from bs4 import BeautifulSoup

headers = {
    'user-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36'
}

home_url = 'http://xa.ganji.com/wu/'
wb_data = requests.get(home_url,headers = headers)
soup = BeautifulSoup(wb_data.text,'lxml')
#print(soup)

utag = soup.select('dl > dt > a[target="_blank"]')

url_list = ''

for item in utag:
    utag_tag = item.get('href')
    #print(utag_tag)
    url = 'http://xa.ganji.com{}'.format(utag_tag)
    url_list = url_list + url + '\n'
    print(url)

獲取完后柜砾,把類目url存儲為變量channel_list,備用。

(2)第二部分代碼:兩個獲取頁面信息的函數(shù)

這一步我們先寫獲取最終頁面鏈接的函數(shù)换衬、再寫通過最終鏈接獲取目標(biāo)信息對應(yīng)的函數(shù)痰驱。
函數(shù)1的參數(shù)有類目鏈接证芭、子頁面編碼兩個,在調(diào)用這個函數(shù)的時(shí)候担映,我們再去寫對應(yīng)的編碼循環(huán)废士、類目循環(huán)。
函數(shù)2的參數(shù)只有最終頁面鏈接一個蝇完。


import pymongo
import requests
from bs4 import BeautifulSoup
import time
from get_ori_url import channel_list,headers


client = pymongo.MongoClient('localhost',27017)
ganji = client['ganji']
#重新建立一個url集
urlset = ganji['urlset']
urlspideset = ganji['urlspideset']
second_info = ganji['second_info']

#step1: get the urls of secondhand
def get_urls(channel,pages):
    url_secondhands = '{}o{}'.format(channel,pages)
    time.sleep(6)
    print(url_secondhands)
    db_urls = [item['url'] for item in channel_sec.find()]
    if url_secondhands in db_urls:
        print('the',url_secondhands,'has spide already!')
        pass
    else:
        wb_data = requests.get(url_secondhands,headers = headers)
        soup = BeautifulSoup(wb_data.text,'lxml')
        #add the url into have spide
        channel_sec.insert_one({'url':url_secondhands})
        #add: if page error,then pass
        url_secondhand = soup.select('dd.feature > div > ul > li > a')
        for item in url_secondhand:
            url_s = item.get('href')
            urlset.insert_one({'url':url_s})
            print(url_s)
        # insert the url had spide into a set;

#step2: get the information we need from the secondhand pages

def get_item_info(url):
    time.sleep(2)
    db_urls = [item['url'] for item in urlspideset.find()]
    if url in db_urls:
        print('the url "',url,'"has aready spide!')
        pass
    else:
        wb_data = requests.get(url,headers=headers)
        soup = BeautifulSoup(wb_data.text,'lxml')
        title = soup.select('h1')
        pagetime = soup.select('div.col-cont.title-box > div > ul.title-info-l.clearfix > li:nth-of-type(1) > i')
        type = soup.select('div.leftBox > div:nth-of-type(3) > div > ul > li:nth-of-type(1) > span > a')
        price = soup.select('div > ul > li:nth-of-type(2) > i.f22.fc-orange.f-type')
        address = soup.select('div.leftBox > div:nth-of-type(3) > div > ul > li:nth-of-type(3)')
        # can't get the pv,need other method
        # pageview = soup.select('pageviews')
        for t1,p1,type1,price1,add1 in zip(title,pagetime,type,price,address):
            data = {
                'title':t1.get_text(),
                'pagetime':(p1.get_text().replace('發(fā)布','')).strip(),
                'type':type1.get_text(),
                'price':price1.get_text(),
                'address':list(add1.stripped_strings)
            }
            second_info.insert_one(data)
            print(data)
        urlspideset.insert_one({'url':url})

(3)第三部分代碼:調(diào)用上述函數(shù)獲取目標(biāo)信息

首先是調(diào)用函數(shù)get_urls官硝,通過類目信息,獲取最終頁面鏈接集:

from multiprocessing import Pool
from get_ori_url import channel_list
from spider_ganji import get_urls

def get_url_from_channel(channel):
    for num in range(1,71):
        get_urls(channel,num)

if __name__ == '__main__':
    pool = Pool()
    pool.map(get_url_from_channel,channel_list.split())

根據(jù)調(diào)用的函數(shù)短蜕,獲取的鏈接會存儲在MongoDB下的ganji庫urlset表中氢架。

再調(diào)用函數(shù) get_item_info,逐個頁面獲取所需信息:


from multiprocessing import Pool
from spider_ganji import get_item_info
from spider_ganji import urlset
from spider_ganji import urlspideset

#get all urls need to spide:
db_urls = [item['url'] for item in urlset.find()]
#get the urls already spide:
url_has_spide = [item['url'] for item in urlspideset.find()]
x = set(db_urls)
y = set(url_has_spide)
rest_urls = x-y

if __name__ == '__main__':
    pool = Pool()
    pool.map(get_item_info,rest_urls)

這一步用了一點(diǎn)去除已爬頁面的技巧:首先是爬的過程中將已爬取url記錄下來(也可以存儲在所爬信息庫中)朋魔,如果出現(xiàn)中斷岖研,用所有需爬取 剔除 已爬取,即可規(guī)避重復(fù)爬取問題警检。
(關(guān)于剔重孙援、規(guī)避中斷過程中出現(xiàn)的問題,應(yīng)該還有更好的解決方案:先記錄異常頁面扇雕、跳過拓售、繼續(xù)爬,最后再處理異常頁面應(yīng)該更合適镶奉?)

3.總結(jié)

大道至簡邻辉,問題的解決方案應(yīng)該是簡潔的,大規(guī)模的數(shù)據(jù)爬取也是一樣:難點(diǎn)并不在于某幾個頁面怎么爬腮鞍,而在于過程上的控制和調(diào)度:調(diào)度過程越清晰值骇,實(shí)現(xiàn)起來越容易,實(shí)現(xiàn)過程中多翻翻文檔就好了(雖然我也覺得文檔看起來累移国,不過確實(shí)還得翻吱瘩,就跟認(rèn)字時(shí)翻字典一樣——現(xiàn)在只需要翻“電子詞典”已經(jīng)很方便了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迹缀,一起剝皮案震驚了整個濱河市使碾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祝懂,老刑警劉巖票摇,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砚蓬,居然都是意外死亡矢门,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祟剔,“玉大人隔躲,你說我怎么就攤上這事∥镅樱” “怎么了宣旱?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叛薯。 經(jīng)常有香客問我浑吟,道長,這世上最難降的妖魔是什么耗溜? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任组力,我火速辦了婚禮,結(jié)果婚禮上强霎,老公的妹妹穿的比我還像新娘忿项。我一直安慰自己,他們只是感情好城舞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布轩触。 她就那樣靜靜地躺著,像睡著了一般家夺。 火紅的嫁衣襯著肌膚如雪脱柱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天拉馋,我揣著相機(jī)與錄音榨为,去河邊找鬼。 笑死煌茴,一個胖子當(dāng)著我的面吹牛随闺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔓腐,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼矩乐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了回论?” 一聲冷哼從身側(cè)響起散罕,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎傀蓉,沒想到半個月后欧漱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葬燎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年误甚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缚甩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡靶草,死狀恐怖蹄胰,靈堂內(nèi)的尸體忽然破棺而出岳遥,到底是詐尸還是另有隱情奕翔,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布浩蓉,位于F島的核電站派继,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捻艳。R本人自食惡果不足惜驾窟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望认轨。 院中可真熱鬧绅络,春花似錦、人聲如沸嘁字。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪蜒。三九已至衷恭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纯续,已是汗流浹背随珠。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猬错,地道東北人窗看。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像倦炒,于是被迫代替她去往敵國和親显沈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容