5行程式碼就能入門爬蟲?

AI科技大本營發表於2019-02-17

640?wx_fmt=jpeg


作者 蘇克1900

來源 | 第2大腦(ID:Mocun6

責編 | swallow


不少讀者是剛剛入門Python或者想學習Python的,今天就來談談如何用快速入門爬蟲。


先說結論:入門爬蟲很容易,幾行程式碼就可以,可以說是學習Python最簡單的途徑。


以我純小白、零基礎的背景來說,入門爬蟲其實很容易,容易在程式碼編寫很簡單,簡單的爬蟲通常幾行就能搞定,而不容易在確定爬蟲的目標,也就是說為什麼要去寫爬蟲,有沒有必要用到爬蟲,是不是手動操作幾乎無法完成,網際網路上有數以百萬千萬計的網站,到底以哪一個網站作為入門首選,這些問題才是難點。所以在動手寫爬蟲前,最好花一些時間想一想這清楚這些問題。


「Talk is cheap. Show me the code」,下面我就以曾寫過的一個爬蟲為例,說一說我是如何快速入門Python爬蟲的。


▌確立目標


第一步,確立目標。


為什麼想起寫這個爬蟲呢,是因為這是曾經在工作中想要解決的問題,當時不會爬蟲,只能用Excel花了數個小時才勉強地把資料爬了下來, 所以在接觸到爬蟲後,第一個想法就是去實現曾未實現的目標。以這樣的方式入門爬蟲,好處顯而易見,就是有了很明確的動力。


很多人學爬蟲都是去爬網上教程中的那些網站,網站一樣就算了,爬取的方法也一模一樣,等於抄一遍,不是說這樣無益,但是會容易導致動力不足,因為你沒有帶著目標去爬,只是為了學爬蟲而爬,爬蟲雖然是門技術活,但是如果能建立在興趣愛好或者工作任務的前提下,學習的動力就會強很多。


在確定好爬蟲目標後,接著我就在腦中預想了想要得到什麼樣的結果、如何展示出來、以什麼形式展現這些問題。所以,我在爬取網站之前,就預先構想出了想要的一個結果,大致是下面這張圖的樣子。


640?wx_fmt=jpeg


目標是利用爬下來的資料,嘗試從不同維度年份、省份、城市去分析全國的股市資訊,然後通過視覺化圖表呈現出來。


拋開資料,可能你會覺得這張圖在排版佈局、色彩搭配、字型文字等方面還挺好看的。這些呢,就跟爬蟲沒什麼關係了,而跟審美有關,提升審美的一種方式是可以通過做PPT來實現,所以你看,我們們說著說著就從爬蟲跳到了 PPT,不得不說我此前發的文章鋪墊地很好啊,哈哈。其實,在職場中,你擁有的技能越多越好。


▌直接開始


確定了目標後,第二步就可以開始寫爬蟲了,如果你像我一樣,之前沒有任何程式設計基礎,那我下面說的思路,可能會有用。


剛開始動手寫爬蟲,我只關注最核心的部分,也就是先成功抓到資料,其他的諸如:下載速度、儲存方式、程式碼條理性等先不管,這樣的程式碼簡短易懂、容易上手,能夠增強信心。


所以,我在寫第一遍的時候,只用了5行程式碼,就成功抓取了全部所需的資訊,當時的感覺就是很爽,覺得爬蟲不過如此啊,自信心爆棚。


1import pandas as pd
2import csv
3for i in range(1,178):  # 爬取全部頁
4    tb = pd.read_html('http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i)))[3
5    tb.to_csv(r'1.csv', mode='a', encoding='utf_8_sig', hea


3000+ 上市公司的資訊,安安靜靜地躺在 Excel 中:


640?wx_fmt=png

▌不斷完善


有了上面的信心後,我開始繼續完善程式碼,因為5行程式碼太單薄,功能也太簡單,大致從以下幾個方面進行了完善:


  • 增加異常處理


由於爬取上百頁的網頁,中途很可能由於各種問題導致爬取失敗,所以增加了 try except 、if 等語句,來處理可能出現的異常,讓程式碼更健壯。


  • 增加程式碼靈活性


初版程式碼由於固定了URL引數,所以只能爬取固定的內容,但是人的想法是多變的,一會兒想爬這個一會兒可能又需要那個,所以可以通過修改 URL 請求引數,來增加程式碼靈活性,從而爬取更靈活的資料。


  • 修改儲存方式


初版程式碼我選擇了儲存到Excel這種最為熟悉簡單的方式,人是一種惰性動物,很難離開自己的舒適區。但是為了學習新知識,所以我選擇將資料儲存到 MySQL 中,以便練習 MySQL 的使用。


  • 加快爬取速度


初版程式碼使用了最簡單的單程式爬取方式,爬取速度比較慢,考慮到網頁數量比較大,所以修改為了多程式的爬取方式。


經過以上這幾點的完善,程式碼量從原先的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()  #計算程式執行時間
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        #可以改報告日期,比如2018-6-30獲得的就是該季度的資訊
19        'pageNum': i   #頁碼
20        }
21        url = 'http://s.askci.com/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()優化程式碼,[0]從pd.read_html返回的list中提取出DataFrame
34    tbl.rename(columns = {'序號':'serial_number''股票程式碼':'stock_code''股票簡稱':'stock_abbre''公司名稱':'company_name''省份':'province''城市':'city''主營業務收入(201712)':'main_bussiness_income''淨利潤(201712)':'net_profit''員工人數':'employees''上市日期':'listing_date''招股書':'zhaogushu''公司財報':'financial_report''行業分類':'industry_classification''產品型別':'industry_type''主營業務':'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表示在原有表基礎上增加,但該表要有表頭
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# # 單程式
67if __name__ == '__main__':    
68    main(178)
69    endtime = time.time()-start_time
70    print('程式執行了%.2f秒' %endtime)
71
72# 多程式
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('程式執行了%.2f秒' %(time.time()-start_time))


雖然程式碼行數增加了不少,但是這個過程卻覺得很自然,因為每次修改都是針對一個小點,一點點去學,搞懂後新增進來,而如果讓我上來就直接寫出這幾十行的程式碼,我很可能就放棄了。


所以,你可以看到,入門爬蟲是有套路的,最重要的是給自己信心。


(本文僅代表作者觀點,轉載請聯絡原作者)

精彩推薦

640?wx_fmt=png

推薦閱讀:

                         640?wx_fmt=png

點選“閱讀原文”,開啟CSDN APP 閱讀更貼心。

相關文章