week2_實(shí)戰(zhàn)作業(yè)

設(shè)計(jì)思路

1.從host頁面獲取趕集網(wǎng)所有城市的二手市場marketurl
2.根據(jù)marketurl獲取每個(gè)板塊的blockurl
3.通過分析各板塊頁腳頁碼元素两残,分析每個(gè)板塊有多少個(gè)列表頁,得到listurl
ps:由于趕集網(wǎng)列表頁設(shè)置非常混亂(如不顯示頁數(shù)控件留攒,只有一頁卻可以訪問任意頁碼等等)塔鳍,此功能并未實(shí)現(xiàn)柒爸,程序只抓取了每個(gè)板塊的第一頁受裹,即blockurl=listurl
4.分析出listurl中的所有詳情頁detailurl
5.解析出詳情頁面中的信息斗这,區(qū)分轉(zhuǎn)轉(zhuǎn)和趕集商品动猬,獲取商品信息
ps:所有信息均入mongodb表中

代碼

main.py

#coding=utf-8
'''爬取趕集網(wǎng)所有城市二手市場所有類目的商品信息,由于趕集網(wǎng)列表頁數(shù)比較混亂表箭,僅抓取各板塊下第一頁
爬取類目下所有帖子,信息包括:商品標(biāo)題,發(fā)帖時(shí)間, 類型,價(jià)格,交易地點(diǎn),新舊程度等
多進(jìn)程方式爬取
'''
from configparser import ConfigParser
from pymongo import MongoClient
from ganji_crawler import get_citys_market,get_block_urls,get_detail_page_urls,getinfo_from_detailpage

cf = ConfigParser()  # 創(chuàng)建conf文件解析對(duì)象
cf.read("ganji.conf")  # 讀取conf文件

host = cf.get('mongodb', 'db_host')
port = cf.getint('mongodb', 'db_port')
client = MongoClient(host, port)  # 連接mongodb赁咙,創(chuàng)建客戶端
ganji_market = client[cf.get('databases', 'db_market')]  # 連接二手市場數(shù)據(jù)庫

# 創(chuàng)建collections實(shí)例
citys_market = ganji_market[cf.get('collections', 'collection_citys')]  # 存放城市url表
city_market_block_url = ganji_market[cf.get('collections', 'collection_block_url')]  # 各城市板塊url表
market_detailpage_url = ganji_market[cf.get('collections', 'collection_detail_url')]  # 詳情頁url
market_goods_infos = ganji_market[cf.get('collections', 'collection_goods_info')]

#############代碼執(zhí)行部分##############
get_citys_market(host,citys_market)   #入庫城市及二手市場url

for city in citys_market.find():
    get_block_urls(city['link'],city_market_block_url)   #入庫板塊url

for block in city_market_block_url.find({}, {'link': 1, '_id': 0}):
    get_detail_page_urls(block['link'],market_detailpage_url) #入庫詳情頁url


for idx, detail in enumerate(market_detailpage_url.find({}, {'link': 1, '_id': 0})):  # 入庫商品信息
    getinfo_from_detailpage(detail['link'], market_goods_infos)
    if idx % 1000 == 0:
        print('{} records has been inserted ! '.format(idx))

crawler.py

#coding=utf-8
'''爬取趕集網(wǎng)二手市場數(shù)據(jù)'''
from bs4 import BeautifulSoup
from pymongo import MongoClient,errors
import requests,re,time

def get_citys_market(host,collection):

    resp = requests.get(host)
    soup = BeautifulSoup(resp.content,'lxml')
    links = soup.select('div.all-city > dl > dd > a ') #獲取城市列表中所有超鏈接
    for link in links:
        collection.insert_one({
            'link' : link['href']+'wu/',
            'city' : link.string
        })

def get_block_urls(city_market_url,collection):
    '''從一個(gè)城市的二手市場頁面抓取所有區(qū)塊url
    city_market_url:某個(gè)城市的二手市場url
    collection:解析出的板塊url存入的數(shù)據(jù)表'''

    resp = requests.get(city_market_url)
    soup = BeautifulSoup(resp.content,'lxml')
    try:
        div_navigate = soup.select('div.main')[0]
    except IndexError:
        return
    for a in div_navigate.select('a'):
        try:
            href = a['href']
            if href.startswith('/'):    #清洗臟數(shù)據(jù),全部分類中有#開頭的
                collection.insert_one({'link': city_market_url[:-4] + href})   #拼拼湊板塊url免钻,這里因?yàn)橼s集網(wǎng)設(shè)置比較特殊彼水,需要去除一些無效字符
        except errors.DuplicateKeyError as e:
            print(e)

def get_detail_page_urls(blockurl,collection):
    '''趕集網(wǎng)板塊的頁數(shù)判斷和訪問就是個(gè)坑啊,完全沒有判斷板塊下有多少頁的規(guī)律极舔,這里先提取各版塊第一頁的詳情頁url'''

    resp = myRequestGet(blockurl)
    if not resp:
        return

    soup = BeautifulSoup(resp.content,'lxml')
    try:
        layoutlist = soup.select('dl.list-bigpic.clearfix') #定位到每條數(shù)據(jù)dl標(biāo)簽上
    except IndexError:
        return
    time.sleep(1)
    for layout in layoutlist:
        links = layout.select('a')  #獲取此標(biāo)簽下所有超鏈
        for link in links:
            href = link['href']
            if href.startswith('http://m.zhuanzhuan.58.com'):       #篩選出轉(zhuǎn)轉(zhuǎn)數(shù)據(jù)url
                #由于獲取的轉(zhuǎn)轉(zhuǎn)url是通過js獲取商品信息的凤覆,所以需要改一下url形式,以便css path可以找到目標(biāo)信息
                infoId = re.findall(r'infoId=(\d+)&', href)[0]
                .format(infoId)
                try:
                    collection.insert_one({'source':'zhuanzhuan','link': href}) #入庫轉(zhuǎn)轉(zhuǎn)url-改寫后
                except errors.DuplicateKeyError as e:
                    print(e)
            elif href.endswith('.htm'):
                try:
                    collection.insert_one({'source':'ganji','link': href})  #入庫趕集url
                except errors.DuplicateKeyError as e:
                    print(e)

def getinfo_from_detailpage(detailurl,collection):
    '''從詳情頁獲取商品信息'''
    resp = myRequestGet(detailurl)
    if not resp:
        return
    soup = BeautifulSoup(resp.content, 'lxml')
    time.sleep(0.1)

    #轉(zhuǎn)轉(zhuǎn)商品信息獲取
    if resp.url.startswith('http://zhuanzhuan'):
        try:
            title = soup.select(' h1.info_titile ')[0].string
            price = ''.join(soup.select(' span.price_now ')[0].stripped_strings)
            area = soup.select(' div.palce_li > span > i ')[0].string
            desc = soup.select(' div.baby_kuang.clearfix > p')[0].string
        except IndexError:
            return
        #入表
        collection.insert_one({
            'source' : 'zhuanzhuan',
            'title': title,
            'price': price,
            'area': area,
            'desc': desc})
    else:   #趕集商品信息獲取
        try:
            title = soup.select(' h1.title-name ')[0].string
            price = soup.select(' i.f22.fc-orange.f-type ')[0].string
            area = ''.join(soup.select(' ul.det-infor > li:nth-of-type(3) ')[0].stripped_strings)
            desc = soup.select(' .second-sum-cont')[0].get_text().strip()
        except IndexError:
            return
        collection.insert_one({
            'source': 'ganji',
            'title': title,
            'price': price,
            'area': area,
            'desc': desc
            })

def myRequestGet(url):
    '''會(huì)遇到被封的情況拆魏,在這里把requests.get包裹一層函數(shù)盯桦,如果異常慈俯,則sleep(10)'''
    try:
        resp = requests.get(url)
        return resp
    except requests.exceptions.RequestException as e:
        print('Requests Error -----------{}-----------wait 10 seconds'.format(str(e.__class__)))
        time.sleep(10)
        return None
    except Exception as e:
        print('Other Eroor -----------{}-----------wait 10 seconds'.format(str(e.__class__)))
        time.sleep(10)
        return None


#判斷頁面是否存在,由于判斷時(shí)需要讀取頁面并生成soup后判斷拥峦,所以干脆傳入soup對(duì)象贴膘,而不是url
def exists(soup):
    if soup.title.string == '您訪問的網(wǎng)頁不存在':
        return False
    else:
        return True


if  __name__ == '__main__':

    ##############一些初始化##############
    client = MongoClient('mongodb://localhost:27017')
    ganji_market = client['ganji_market']    #趕集網(wǎng)二手市場數(shù)據(jù)庫
    host = 'http://www.ganji.com/index.htm'

    #創(chuàng)建存儲(chǔ)城市及其二手市場url的表
    citys_market = ganji_market['citys_market']

    #創(chuàng)建存儲(chǔ)各城市二手市場板塊url的collections,并將link字段設(shè)置為唯一索引略号,避免出現(xiàn)重復(fù)的link
    city_market_block_url = ganji_market['city_market_block_url']
    city_market_block_url.ensure_index('link', unique=True)


    #創(chuàng)建詳情頁url存儲(chǔ)表
    market_detailpage_url = ganji_market['market_detailpage_url']
    market_detailpage_url.ensure_index('link', unique=True)

    #商品信息入庫
    market_goods_infos = ganji_market['market_goods_infos']

    ##############代碼執(zhí)行部分##############
    # get_citys_market(host,citys_market)   #入庫城市及二手市場url
    # get_citys_market(host)

    # for city in citys_market.find():
    #     get_block_urls(city['link'],city_market_block_url)   #入庫板塊url
    # get_block_urls('http://xa.ganji.com/wu/')

    # for block in city_market_block_url.find({}, {'link': 1, '_id': 0}):
    #     get_detail_page_urls(block['link'],market_detailpage_url) #入庫詳情頁url
    # get_detail_page_urls('http://xa.ganji.com/ershoubijibendiannao/')


    for idx,detail in enumerate(market_detailpage_url.find({}, {'link': 1, '_id': 0}).skip(12000)):  #入庫商品信息
        getinfo_from_detailpage(detail['link'],market_goods_infos)
        if idx % 1000 == 0:
            print ('{} records has been inserted ! '.format(idx))

    # getinfo_from_detailpage('http://zhuanzhuan.58.com/detail/755842657703362564z.shtml')
    # getinfo_from_detailpage('http://xa.ganji.com/ershoubijibendiannao/2266604261x.htm')

ganji.conf

[mongodb]
db_host = localhost
db_port = 27017

[databases]
db_market = ganji_market

[collections]
collection_citys = citys_market
collection_block_url =  city_market_block_url
collection_detail_url = market_detailpage_url
collection_goods_info = market_goods_infos

總結(jié)

1.沒有使用多進(jìn)程刑峡,是因?yàn)楹瘮?shù)都要傳入兩個(gè)參數(shù)(包括一個(gè)collection對(duì)象),暫且先不修改函數(shù)適用map方式了玄柠。multiprocessing和threading模塊還需要再學(xué)習(xí)一下
2.為了增強(qiáng)程序健壯性突梦,執(zhí)行過程中增加了一些try模塊,在遇到爬蟲被封的時(shí)候停頓10s再接著抓取随闪,目前看效果不錯(cuò)
3.抓取是按照模板設(shè)計(jì)的阳似,通用性的問題依然存在,不知是否可以使用scrapy解決
4.引入了一個(gè)configparser模塊來創(chuàng)建配置文件讀取相關(guān)信息铐伴,以后可以繼續(xù)使用
5.由于爬蟲被封撮奏,商品詳情url僅抓取了20w,因此商品信息也僅能解析出這么多当宴。后增加了程序的健壯性畜吊,未重新運(yùn)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末户矢,一起剝皮案震驚了整個(gè)濱河市玲献,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梯浪,老刑警劉巖捌年,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挂洛,居然都是意外死亡礼预,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門虏劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來托酸,“玉大人,你說我怎么就攤上這事柒巫±ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵堡掏,是天一觀的道長应结。 經(jīng)常有香客問我,道長泉唁,這世上最難降的妖魔是什么摊趾? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任币狠,我火速辦了婚禮,結(jié)果婚禮上砾层,老公的妹妹穿的比我還像新娘漩绵。我一直安慰自己,他們只是感情好肛炮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布止吐。 她就那樣靜靜地躺著,像睡著了一般侨糟。 火紅的嫁衣襯著肌膚如雪碍扔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天秕重,我揣著相機(jī)與錄音不同,去河邊找鬼。 笑死溶耘,一個(gè)胖子當(dāng)著我的面吹牛二拐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凳兵,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼百新,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了庐扫?” 一聲冷哼從身側(cè)響起饭望,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎形庭,沒想到半個(gè)月后铅辞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萨醒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年斟珊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片验靡。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡倍宾,死狀恐怖雏节,靈堂內(nèi)的尸體忽然破棺而出胜嗓,到底是詐尸還是另有隱情,我是刑警寧澤钩乍,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布辞州,位于F島的核電站,受9級(jí)特大地震影響寥粹,放射性物質(zhì)發(fā)生泄漏变过。R本人自食惡果不足惜埃元,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媚狰。 院中可真熱鬧岛杀,春花似錦、人聲如沸崭孤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辨宠。三九已至遗锣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗤形,已是汗流浹背精偿。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赋兵,地道東北人笔咽。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像毡惜,于是被迫代替她去往敵國和親拓轻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • 結(jié)果: 作業(yè)項(xiàng)目地址 總結(jié) 如何判斷是否是最后一頁 兩種實(shí)現(xiàn)思路 1经伙,是否有分頁符 如果沒有扶叉,pass 2,是否元...
    超net閱讀 3,937評(píng)論 1 4
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評(píng)論 25 707
  • 1 前言 作為一名合格的數(shù)據(jù)分析師帕膜,其完整的技術(shù)知識(shí)體系必須貫穿數(shù)據(jù)獲取枣氧、數(shù)據(jù)存儲(chǔ)、數(shù)據(jù)提取垮刹、數(shù)據(jù)分析达吞、數(shù)據(jù)挖掘、...
    whenif閱讀 18,070評(píng)論 45 523
  • 秋雨綿綿身是客荒典,前路茫茫未可知酪劫, 年少輕狂比天高,卻如蜉蟻命漂泊寺董, 自古英雄多磨難覆糟,無路草莽奔瓦崗, 綠林自有綠林...
    云水解心閱讀 449評(píng)論 1 7
  • 前些天拜讀了村上春樹的作品《眠》 頗有同感 不知道有多少人飽受失眠的折磨 有多少個(gè)夜里輾轉(zhuǎn)反側(cè) 夜不能寐 不管是學(xué)...
    不識(shí)故閱讀 279評(píng)論 2 3