不少讀者是剛剛?cè)腴TPython或者想學(xué)習(xí)Python的,今天就來談?wù)?strong>如何用快速入門爬蟲。 先說結(jié)論:入門爬蟲很容易,幾行代碼就可以,可以說是學(xué)習(xí)Python最簡單的途徑。 以我純小白、零基礎(chǔ)的背景來說,入門爬蟲其實(shí)很容易,容易在代碼編寫很簡單,簡單的爬蟲通常幾行就能搞定,而不容易在確定爬蟲的目標(biāo),也就是說為什么要去寫爬蟲,有沒有必要用到爬蟲,是不是手動操作幾乎無法完成,互聯(lián)網(wǎng)上有數(shù)以百萬千萬計(jì)的網(wǎng)站,到底以哪一個網(wǎng)站作為入門首選,這些問題才是難點(diǎn)。所以在動手寫爬蟲前,最好花一些時間想一想這清楚這些問題。 「Talk is cheap. Show me the code」,下面我就以曾寫過的一個爬蟲為例,說一說我是如何快速入門Python爬蟲的。(私信我python,獲得萬元python學(xué)習(xí)大禮包!) ▌確立目標(biāo) 第一步,確立目標(biāo)。 為什么想起寫這個爬蟲呢,是因?yàn)檫@是曾經(jīng)在工作中想要解決的問題,當(dāng)時不會爬蟲,只能用Excel花了數(shù)個小時才勉強(qiáng)地把數(shù)據(jù)爬了下來, 所以在接觸到爬蟲后,第一個想法就是去實(shí)現(xiàn)曾未實(shí)現(xiàn)的目標(biāo)。以這樣的方式入門爬蟲,好處顯而易見,就是有了很明確的動力。 很多人學(xué)爬蟲都是去爬網(wǎng)上教程中的那些網(wǎng)站,網(wǎng)站一樣就算了,爬取的方法也一模一樣,等于抄一遍,不是說這樣無益,但是會容易導(dǎo)致動力不足,因?yàn)槟銢]有帶著目標(biāo)去爬,只是為了學(xué)爬蟲而爬,爬蟲雖然是門技術(shù)活,但是如果能建立在興趣愛好或者工作任務(wù)的前提下,學(xué)習(xí)的動力就會強(qiáng)很多。 在確定好爬蟲目標(biāo)后,接著我就在腦中預(yù)想了想要得到什么樣的結(jié)果、如何展示出來、以什么形式展現(xiàn)這些問題。所以,我在爬取網(wǎng)站之前,就預(yù)先構(gòu)想出了想要的一個結(jié)果,大致是下面這張圖的樣子。 目標(biāo)是利用爬下來的數(shù)據(jù),嘗試從不同維度年份、省份、城市去分析全國的股市信息,然后通過可視化圖表呈現(xiàn)出來。 拋開數(shù)據(jù),可能你會覺得這張圖在排版布局、色彩搭配、字體文字等方面還挺好看的。這些呢,就跟爬蟲沒什么關(guān)系了,而跟審美有關(guān),提升審美的一種方式是可以通過做PPT來實(shí)現(xiàn),所以你看,咱們說著說著就從爬蟲跳到了 PPT,不得不說我此前發(fā)的文章鋪墊地很好啊,哈哈。其實(shí),在職場中,你擁有的技能越多越好。 ▌直接開始 確定了目標(biāo)后,第二步就可以開始寫爬蟲了,如果你像我一樣,之前沒有任何編程基礎(chǔ),那我下面說的思路,可能會有用。 剛開始動手寫爬蟲,我只關(guān)注最核心的部分,也就是先成功抓到數(shù)據(jù),其他的諸如:下載速度、存儲方式、代碼條理性等先不管,這樣的代碼簡短易懂、容易上手,能夠增強(qiáng)信心。 所以,我在寫第一遍的時候,只用了5行代碼,就成功抓取了全部所需的信息,當(dāng)時的感覺就是很爽,覺得爬蟲不過如此啊,自信心爆棚。 import pandas as pd
import csv
for i in range(1,178): # 爬取全部頁
tb = pd.read_html('http://s./stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i)))[3]
tb.to_csv(r'1.csv', mode='a', encoding='utf_8_sig', hea 3000 上市公司的信息,安安靜靜地躺在 Excel 中: ▌不斷完善 有了上面的信心后,我開始繼續(xù)完善代碼,因?yàn)?行代碼太單薄,功能也太簡單,大致從以下幾個方面進(jìn)行了完善:
由于爬取上百頁的網(wǎng)頁,中途很可能由于各種問題導(dǎo)致爬取失敗,所以增加了 try except 、if 等語句,來處理可能出現(xiàn)的異常,讓代碼更健壯。
初版代碼由于固定了URL參數(shù),所以只能爬取固定的內(nèi)容,但是人的想法是多變的,一會兒想爬這個一會兒可能又需要那個,所以可以通過修改 URL 請求參數(shù),來增加代碼靈活性,從而爬取更靈活的數(shù)據(jù)。
初版代碼我選擇了存儲到Excel這種最為熟悉簡單的方式,人是一種惰性動物,很難離開自己的舒適區(qū)。但是為了學(xué)習(xí)新知識,所以我選擇將數(shù)據(jù)存儲到 MySQL 中,以便練習(xí) MySQL 的使用。
初版代碼使用了最簡單的單進(jìn)程爬取方式,爬取速度比較慢,考慮到網(wǎng)頁數(shù)量比較大,所以修改為了多進(jìn)程的爬取方式。 經(jīng)過以上這幾點(diǎn)的完善,代碼量從原先的5行增加到了下面的幾十行: 1import requests 2import pandas as pd 3from bs4 import BeautifulSoup 4from lxml import etree 5import time 6import pymysql 7from sqlalchemy import create_engine 8from urllib.parse import urlencode # 編碼 URL 字符串 9 10start_time = time.time() #計(jì)算程序運(yùn)行時間 11def get_one_page(i): 12 try: 13 headers = { 14 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36' 15 } 16 paras = { 17 'reportTime': '2017-12-31', 18 #可以改報(bào)告日期,比如2018-6-30獲得的就是該季度的信息 19 'pageNum': i #頁碼 20 } 21 url = 'http://s./stock/a/?' urlencode(paras) 22 response = requests.get(url,headers = headers) 23 if response.status_code == 200: 24 return response.text 25 return None 26 except RequestException: 27 print('爬取失敗') 28 29def parse_one_page(html): 30 soup = BeautifulSoup(html,'lxml') 31 content = soup.select('#myTable04')[0] #[0]將返回的list改為bs4類型 32 tbl = pd.read_html(content.prettify(),header = 0)[0] 33 # prettify()優(yōu)化代碼,[0]從pd.read_html返回的list中提取出DataFrame 34 tbl.rename(columns = {'序號':'serial_number', '股票代碼':'stock_code', '股票簡稱':'stock_abbre', '公司名稱':'company_name', '省份':'province', '城市':'city', '主營業(yè)務(wù)收入(201712)':'main_bussiness_income', '凈利潤(201712)':'net_profit', '員工人數(shù)':'employees', '上市日期':'listing_date', '招股書':'zhaogushu', '公司財(cái)報(bào)':'financial_report', '行業(yè)分類':'industry_classification', '產(chǎn)品類型':'industry_type', '主營業(yè)務(wù)':'main_business'},inplace = True) 35 return tbl 36 37def generate_mysql(): 38 conn = pymysql.connect( 39 host='localhost', 40 user='root', 41 password='******', 42 port=3306, 43 charset = 'utf8', 44 db = 'wade') 45 cursor = conn.cursor() 46 47 sql = 'CREATE TABLE IF NOT EXISTS listed_company (serial_number INT(20) NOT NULL,stock_code INT(20) ,stock_abbre VARCHAR(20) ,company_name VARCHAR(20) ,province VARCHAR(20) ,city VARCHAR(20) ,main_bussiness_income VARCHAR(20) ,net_profit VARCHAR(20) ,employees INT(20) ,listing_date DATETIME(0) ,zhaogushu VARCHAR(20) ,financial_report VARCHAR(20) , industry_classification VARCHAR(20) ,industry_type VARCHAR(100) ,main_business VARCHAR(200) ,PRIMARY KEY (serial_number))' 48 cursor.execute(sql) 49 conn.close() 50 51def write_to_sql(tbl, db = 'wade'): 52 engine = create_engine('mysql pymysql://root:******@localhost:3306/{0}?charset=utf8'.format(db)) 53 try: 54 tbl.to_sql('listed_company2',con = engine,if_exists='append',index=False) 55 # append表示在原有表基礎(chǔ)上增加,但該表要有表頭 56 except Exception as e: 57 print(e) 58 59def main(page): 60 generate_mysql() 61 for i in range(1,page): 62 html = get_one_page(i) 63 tbl = parse_one_page(html) 64 write_to_sql(tbl) 65 66# # 單進(jìn)程 67if __name__ == '__main__': 68 main(178) 69 endtime = time.time()-start_time 70 print('程序運(yùn)行了%.2f秒' %endtime) 71 72# 多進(jìn)程 73from multiprocessing import Pool 74if __name__ == '__main__': 75 pool = Pool(4) 76 pool.map(main, [i for i in range(1,178)]) #共有178頁 77 endtime = time.time()-start_time 78 print('程序運(yùn)行了%.2f秒' %(time.time()-start_time)) 雖然代碼行數(shù)增加了不少,但是這個過程卻覺得很自然,因?yàn)槊看涡薷亩际轻槍σ粋€小點(diǎn),一點(diǎn)點(diǎn)去學(xué),搞懂后添加進(jìn)來,而如果讓我上來就直接寫出這幾十行的代碼,我很可能就放棄了。 所以,你可以看到,入門爬蟲是有套路的,最重要的是給自己信心。 |
|