python爬蟲的最佳實踐(六)--爬蟲中的多程式

weixin_34146805發表於2016-05-05

ps:寫給新手看的,大神看到了輕噴,給我留點面子~

寫在前面

為什麼選用多程式而不選用多執行緒,這是考慮到了諸多的實際情況最終做出的選擇。

  • 在python環境下,多程式稍稍比多執行緒好實現好理解一點。
  • 因為爬蟲大多數都是執行在linux核心的伺服器上面,而在linux作業系統下,多程式要比多執行緒更加合適,因為排程開銷和多執行緒差不多,但是程式效能更好。如果在windows系統下跑爬蟲的話,建議使用框架或者使用多執行緒。
  • 爬蟲畢竟不是伺服器互動,沒有人會開1k的執行緒去跑這個,所以一般情況下我們把自己爬蟲的效率提升幾倍即可。

有興趣的同學可以去看一下程式和執行緒的區別,據說面試容易被問喔我們今天就講一下簡單的多程式的實現就好了,如果你想深入爬蟲效率研究可以好好研究一下多程式和多執行緒相關

程式碼預覽

#coding:utf-8
import multiprocessing
from bs4 import BeautifulSoup
import requests

def pageUrls(url):
    web_data = requests.get(url)
    soup = BeautifulSoup(web_data.text, 'lxml')
    sum = int(soup.select('span.total > em:nth-of-type(1)')[0].get_text())
    pageNum = sum/50
    return [url+'/loupan/s?p={}'.format(str(i)) for i in range(1, pageNum+2, 1)]

def detailPage(myurl):
    urls = pageUrls(myurl)
    for url in urls:
        web_data = requests.get(url)
        soup = BeautifulSoup(web_data.text, 'lxml')
        titles = soup.select('div.list-results > div.key-list > div > div.infos > div > h3 > a')
        for title in titles:
            print url
            print title.get_text()
            print title.get('href')

def main(urls):
    pool = multiprocessing.Pool(multiprocessing.cpu_count())
    for url in urls:
        pool.apply_async(detailPage, (url, ))
    # pool.map(detailPage, urls)
    pool.close()
    pool.join()


if __name__ == "__main__":
    startUrl = 'http://tj.fang.anjuke.com/?from=navigation'
    web_data = requests.get(startUrl)
    soup = BeautifulSoup(web_data.text, 'lxml')
    urls = [url.get('href') for url in soup.select('.city-mod > dl > dd > a')]
    main(urls)

程式碼剖析

if __name__ == "__main__":
    startUrl = 'http://tj.fang.anjuke.com/?from=navigation'
    web_data = requests.get(startUrl)
    soup = BeautifulSoup(web_data.text, 'lxml')
    urls = [url.get('href') for url in soup.select('.city-mod > dl > dd > a')]
    main(urls)

在這裡講一個小知識點,if __name__ == "__main__":這段程式碼的作用是保證在這個py檔案被import的時候不會被執行,只有主動執行它的時候才會執行。
這次我們扒取的是安居客的住房資訊,上面那一段程式碼相信大家都能看懂,從入口進入,取到全國各地城市的連結,然後進入main函式

pool = multiprocessing.Pool(multiprocessing.cpu_count())
multiprocessing是python中標準的多程式庫,上面程式碼的意思是建立一個程式池,程式個數為cpu核心數。這裡有個小知識,電腦的cpu有多少核心便可以同時執行多少個程式,當然你也可以填的很多,只是作用不大而已,並不是程式數越多就會執行的越快。

pool.apply_async(detailPage, (url, ))
apply_async函式從程式池中取出一個程式執行func,args為func的引數,我們這段程式碼不斷地從程式池中取出程式去執行我們的detailPage方法。當然,也可以採用下面哪種方式:
pool.map(detailPage, urls)
map方法,將detailPage()函式作用到表的每個元素上,表中每個元素都會被作用到。這兩種方式都可以~

pool.close()關閉程式池,程式池不會再建立新的程式
pool.join()wait程式池中的全部程式,也就是用來等待程式池中的worker程式執行完畢,防止主程式在worker程式結束前結束

這樣,對於我的電腦來說等於開了8個程式去並行爬蟲(沒做反扒一會就會被封了哈哈),經過我測試速度比單個程式快了4倍左右,還是很有用的~

剩下的兩個函式我就不多贅述了pageUrls,根據頁面上資料量的多少生成page分頁的url,detailPage扒取每個page分頁的所有樓盤的標題資訊。

今天我們介紹了多程式,同時,實踐瞭如何從網站的一個入口延伸進而抓取整個網站的內容。當然,每個人寫程式碼的習慣不同,當你多多練習的時候自然有自己的方式去實現你想要的功能。

ps:今天突然想起來,大家在做爬蟲的時候儘量先扒到連結,存在資料庫之後再去扒分頁裡面的詳細內容,因為這樣速度不慢而且容錯率很高,也很容易做斷點續扒~

寫在最後

經過前面幾章的學習,我相信你已經可以扒取大部分網站了,並且有不錯的效率。下一章我們將學習py爬蟲的框架pyspider我覺得還是很好用的

有興趣的同學可以加群498945822一起交流學習哦~~
發現問題的同學歡迎指正,直接說就行,不用留面子,博主臉皮厚!

相關文章