初試python爬蟲實(shí)戰(zhàn)三——爬取考研幫導(dǎo)師簡介

1 基礎(chǔ)版本

1.1 抓取首頁鏈接碌秸,依次訪問

與前兩次實(shí)戰(zhàn)的區(qū)別不大丈攒,所以這次嘗試模塊化編程苞也。不再寫之前腳本式的代碼菩貌。寫完代碼之后來寫的博客教寂,所以只簡單記一下編碼過程中遇到的問題以及解決方案伪节。

  • requests請求返回的數(shù)據(jù)出現(xiàn)了中文亂碼
    仔細(xì)分析了一下頁面缅叠,考研幫該頁面的源代碼為:
 <html lang="zh">
  <head>
    ...

猜想還是編碼的問題舔哪。所以在requests的請求中,最終返回做一個(gè)編碼處理:

 # 出現(xiàn)中文亂碼的解決方法
    resp.encoding = 'utf-8'
  • 取出的數(shù)據(jù)中包含大量的‘\r’ '\t' '\u' '\u3000'等控制字符铺峭。解決辦法為在requests之后墓怀,返回?cái)?shù)據(jù)之前做一個(gè).replece處理:
 resp = resp.text.replace('\t', '')
              .replace('\r', '')
              .replace('\n', '').replace('\u3000', '')

基礎(chǔ)版本首頁最終代碼:

import time
import requests
from lxml import etree

start_url = 'http://www.kaoyan.com/daoshi/'
titles = []
context = []
data = {}


# 訪問
def get_resp(url):
    ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' \
         'AppleWebKit/537.36 (KHTML, like Gecko) ' \
         'Chrome/80.0.3987.116 Safari/537.36'
    header = {'User-Agent': ua}
    resp = requests.get(url, headers=header)
    # 出現(xiàn)中文亂碼的解決方法
    resp.encoding = 'utf-8'
    if resp.status_code == 200:
        # return resp.text
        resp = resp.text.replace('\t', '').replace('\r', '').replace('\n', '').replace('\u3000', '')
        return resp
    else:
        print(url + '訪問失敗')


def parse_teacher(resp_page):

    et = etree.HTML(resp_page)
    if et is not None:
        # 處理標(biāo)題
        selectors = et.xpath('//h1')
        titles.append(selectors[0].text)

        # 處理詳情介紹
        selectors2 = et.xpath("http://div[@class='articleCon']//p/text()")
        text = ''
        for s in selectors2:
            text += s
        context.append(text)

    else:
        print('發(fā)現(xiàn)一個(gè)異常頁面,已跳過')


# 處理鏈接卫键,依次訪問超鏈接
def link_parse(resp):
    et = etree.HTML(resp)
    links = et.xpath("http://ul[@class='list areaZslist']/li//a/@href")
    for link in links:
        resp_page = get_resp(link)
        parse_teacher(resp_page)


def make_and_print():
    data.update(zip(titles, context))
    print(data)


if __name__ == '__main__':
    start_time = time.time()

    # 訪問初始url
    resp = get_resp(start_url)
    # 處理鏈接 循環(huán)訪問下載
    link_parse(resp)
    # 處理最終數(shù)據(jù)并輸出
    make_and_print()

    last_time = time.time() - start_time
    print(last_time)

輸出效果為:


V1效果

1.2 獲取下一頁

這種數(shù)據(jù)值抓取一頁當(dāng)然是毫無意義的傀履,下面要做的是檢查頁面是否存在下一頁,如果存在莉炉,再繼續(xù)加載下一頁钓账。核心代碼為:

# 多頁處理
    next_url = et.xpath('//div[4]/a[11]/@href')
    if next_url:
        print('下一頁地址:', next_url[0])
        r = get_resp(next_url[0])
        link_parse(r)
    else:
        print('頁面加載完畢,開始逐個(gè)下載導(dǎo)師資料絮宁,請稍后...')

1.3 保存到記事本

以title為文件名梆暮,將各個(gè)導(dǎo)師信息保存到記事本中。

def save_data(path, dicta):
    if not os.path.exists(path):
        os.mkdir(os.getcwd() + '\\data_out')
    os.chdir(path)
    for k, v in dicta.items():
        filename = k+'.txt'
        file_context = v
        f = open(filename, 'w+', encoding='utf-8')
        f.write(file_context)
        f.seek(0)
        f.close()
        print(k, '資料保存完成绍昂!')

實(shí)現(xiàn)的效果為:


最終效果1
最終效果2
最終效果3

完美實(shí)現(xiàn)需求啦粹。第一部分結(jié)束。第一部分最終完整代碼:

import time
import os
import requests
from lxml import etree

start_url = 'http://www.kaoyan.com/daoshi/'
titles = []
context = []
data = {}


# 訪問
def get_resp(url):
    ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' \
         'AppleWebKit/537.36 (KHTML, like Gecko) ' \
         'Chrome/80.0.3987.116 Safari/537.36'
    header = {'User-Agent': ua}
    resp = requests.get(url, headers=header)
    # 出現(xiàn)中文亂碼的解決方法
    resp.encoding = 'utf-8'
    if resp.status_code == 200:
        # return resp.text
        resp = resp.text.replace('\t', '') \
            .replace('\r', '') \
            .replace('\n', '') \
            .replace('\u3000', '') \
            .replace('\xa0', '')
        return resp
    else:
        print(url + '訪問失敗')


def parse_teacher(resp_page):
    et = etree.HTML(resp_page)
    if et is not None:
        # 處理標(biāo)題
        selectors = et.xpath('//h1')
        titles.append(selectors[0].text)

        # 處理詳情介紹
        selectors2 = et.xpath("http://div[@class='articleCon']//p/text()")
        text = ''
        for s in selectors2:
            text += s
        context.append(text)

    else:
        print('發(fā)現(xiàn)一個(gè)異常頁面窘游,已跳過')


# 處理鏈接唠椭,依次訪問超鏈接
def link_parse(resp):
    et = etree.HTML(resp)
    links = et.xpath("http://ul[@class='list areaZslist']/li//a/@href")
    # 多頁處理
    next_url = et.xpath('//div[4]/a[11]/@href')
    if next_url:
        print('下一頁地址:', next_url[0])
        r = get_resp(next_url[0])
        link_parse(r)
    else:
        print('頁面加載完畢,開始逐個(gè)下載導(dǎo)師資料张峰,請稍后...')
    for link in links:
        resp_page = get_resp(link)
        parse_teacher(resp_page)


def make_and_print():
    data.update(zip(titles, context))
    print(data)


def save_data(path, dicta):
    if not os.path.exists(path):
        os.mkdir(os.getcwd() + '\\data_out')
    os.chdir(path)
    for k, v in dicta.items():
        filename = k+'.txt'
        file_context = v
        f = open(filename, 'w+', encoding='utf-8')
        f.write(file_context)
        f.seek(0)
        f.close()
        print(k, '資料保存完成泪蔫!')


if __name__ == '__main__':
    start_time = time.time()
    # save_data('./data_out', data)

    # 訪問初始url
    resp = get_resp(start_url)
    # 處理鏈接 循環(huán)訪問下載
    link_parse(resp)
    # 處理最終數(shù)據(jù)并輸出
    make_and_print()
    save_data('./data_out', data)

    print(len(titles))
    last_time = time.time() - start_time
    print(last_time)

2.多線程版

雖然數(shù)據(jù)量比較小,耗費(fèi)的時(shí)間也并不多喘批。但是覺得前面的多線程還是沒怎么理解,再寫一個(gè)demo試試吧~
首先導(dǎo)入threading系統(tǒng)庫铣揉。注意ing饶深。導(dǎo)入Queue用于存放鏈接隊(duì)列。

import threading

定義一個(gè)變量逛拱,控制線程個(gè)數(shù)敌厘。定義一個(gè)線程池,保存線程朽合。定義一個(gè)鏈接隊(duì)列

thread_num = 10
threads = []
links_queue = Queue()

在鏈接處理函數(shù)中俱两,將所有鏈接存入隊(duì)列。

 for link in links:
        links_queue.put(link)

在主函數(shù)中創(chuàng)建線程

 for t in range(thread_num):
        t = threading.Thread(target=download)
        t.start()
        threads.append(t)

編寫download()方法

def download():
    while True:
        link = links_queue.get()
        if link is None:
            break
        resp_page = get_resp(link)
        parse_teacher(resp_page)
        print('當(dāng)前下載線程數(shù):%s,剩余%s條鏈接未解析' %
              (len(threading.enumerate())-1, links_queue.qsize()))

依次退出線程

    for i in range(thread_num):
        links_queue.put(None)
    for t in threads:
        t.join()

實(shí)際效果明顯增快

效果1
效果2
效果3

與單線程相比曹步,增速一倍以上宪彩!

貼出多線程版完整代碼:

# 多線程爬取導(dǎo)師信息
import time
import os
import threading
from queue import Queue
import requests
from lxml import etree

start_url = 'http://www.kaoyan.com/daoshi/'
titles = []
context = []
data = {}

thread_num = 10
threads = []
links_queue = Queue()


# 訪問
def get_resp(url):
    ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' \
         'AppleWebKit/537.36 (KHTML, like Gecko) ' \
         'Chrome/80.0.3987.116 Safari/537.36'
    header = {'User-Agent': ua}
    resp = requests.get(url, headers=header)
    # 出現(xiàn)中文亂碼的解決方法
    resp.encoding = 'utf-8'
    if resp.status_code == 200:
        # return resp.text
        resp = resp.text.replace('\t', '') \
            .replace('\r', '') \
            .replace('\n', '') \
            .replace('\u3000', '') \
            .replace('\xa0', '')
        return resp
    else:
        print(url + '訪問失敗')


def parse_teacher(resp_page):
    et = etree.HTML(resp_page)
    if et is not None:
        # 處理標(biāo)題
        selectors = et.xpath('//h1')
        titles.append(selectors[0].text)

        # 處理詳情介紹
        selectors2 = et.xpath("http://div[@class='articleCon']//p/text()")
        text = ''
        for s in selectors2:
            text += s
        context.append(text)

    else:
        print('發(fā)現(xiàn)一個(gè)異常頁面,已跳過')


# 處理鏈接讲婚,依次訪問超鏈接
def link_parse(resp):
    et = etree.HTML(resp)
    links = et.xpath("http://ul[@class='list areaZslist']/li//a/@href")
    # 多頁處理
    next_url = et.xpath('//div[4]/a[11]/@href')
    if next_url:
        print('下一頁地址:', next_url[0])
        r = get_resp(next_url[0])
        link_parse(r)
    else:
        print('頁面加載完畢尿孔,開始逐個(gè)下載導(dǎo)師資料,請稍后...')
    for link in links:
        links_queue.put(link)
        # resp_page = get_resp(link)
        # parse_teacher(resp_page)


def make_and_print():
    data.update(zip(titles, context))
    print(data)


def save_data(path, dicta):
    if not os.path.exists(path):
        os.mkdir(os.getcwd() + '\\data_out')
    os.chdir(path)
    for k, v in dicta.items():
        filename = k+'.txt'
        file_context = v
        f = open(filename, 'w+', encoding='utf-8')
        f.write(file_context)
        f.seek(0)
        f.close()
        print(k, '資料保存完成!')


def download():
    while True:
        link = links_queue.get()
        if link is None:
            break
        resp_page = get_resp(link)
        parse_teacher(resp_page)
        print('當(dāng)前下載線程數(shù):%s,剩余%s條鏈接未解析' %
              (len(threading.enumerate())-1, links_queue.qsize()))


if __name__ == '__main__':
    start_time = time.time()
    # 訪問初始url
    resp = get_resp(start_url)
    # 處理鏈接 循環(huán)訪問下載
    link_parse(resp)

    for t in range(thread_num):
        t = threading.Thread(target=download)
        t.start()
        threads.append(t)

    for i in range(thread_num):
        links_queue.put(None)
    for t in threads:
        t.join()

    # 處理最終數(shù)據(jù)并輸出
    make_and_print()
    save_data('./data_out', data)

    last_time = time.time() - start_time
    print('共下載%s條導(dǎo)師信息活合,耗時(shí)%s秒' % (len(titles), last_time))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雏婶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子白指,更是在濱河造成了極大的恐慌留晚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件告嘲,死亡現(xiàn)場離奇詭異错维,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)状蜗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門需五,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人轧坎,你說我怎么就攤上這事宏邮。” “怎么了缸血?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵蜜氨,是天一觀的道長。 經(jīng)常有香客問我捎泻,道長飒炎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任笆豁,我火速辦了婚禮郎汪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闯狱。我一直安慰自己煞赢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布哄孤。 她就那樣靜靜地躺著照筑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瘦陈。 梳的紋絲不亂的頭發(fā)上凝危,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音晨逝,去河邊找鬼蛾默。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咏花,可吹牛的內(nèi)容都是我干的趴生。 我是一名探鬼主播阀趴,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苍匆!你這毒婦竟也來了刘急?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浸踩,失蹤者是張志新(化名)和其女友劉穎叔汁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體检碗,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡据块,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了折剃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片另假。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怕犁,靈堂內(nèi)的尸體忽然破棺而出边篮,到底是詐尸還是另有隱情,我是刑警寧澤奏甫,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布戈轿,位于F島的核電站,受9級特大地震影響阵子,放射性物質(zhì)發(fā)生泄漏思杯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一挠进、第九天 我趴在偏房一處隱蔽的房頂上張望色乾。 院中可真熱鬧,春花似錦领突、人聲如沸杈湾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至殴泰,卻和暖如春于宙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悍汛。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工捞魁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人离咐。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓谱俭,卻偏偏與公主長得像奉件,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子昆著,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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

  • 首先我們需要知道凑懂,學(xué)習(xí)任何一門語言都離不開查閱她的官方文檔煤痕,那么Kotlin的官方文檔地址為: http://ko...
    北方素素閱讀 973評論 0 1
  • 小時(shí)候我很愛哭,媽媽每次都會(huì)會(huì)說接谨,你再哭就讓警察把你帶走摆碉。長大之后,和一個(gè)警察談了兩年戀愛脓豪,雙方家里也因此吵了兩年...
    童young精彩閱讀 396評論 0 0
  • "想結(jié)婚的就去結(jié)婚巷帝,想離婚的就去離婚,想單身的就維持單身扫夜,反正到最后都會(huì)后悔楞泼。"今天突然看到這句話,覺得好毒又很有道理历谍。
    Miss浮游閱讀 153評論 0 1
  • 文|木槿琳 像我這樣的人是怎樣的人现拒? 優(yōu)秀的,聰明的卻又在迷茫望侈、尋找印蔬,有點(diǎn)庸俗,有點(diǎn)碌碌無為脱衙,會(huì)懦弱侥猬,會(huì)孤單,卻又...
    木槿琳閱讀 970評論 12 10
  • 目錄: Django教程(一)- Django視圖與網(wǎng)址Django教程(二)- Django視圖與網(wǎng)址進(jìn)階Dja...
    一只寫程序的猿閱讀 2,929評論 0 5