(數據科學學習手札33)基於Python的網絡數據採集實戰(1)

1、簡介html

  前面兩篇文章咱們圍繞利用Python進行網絡數據採集鋪墊了不少內容,但光說不練是不行的,因而乎,本篇就將基於筆者最近的一項數據需求進行一次網絡數據採集的實戰;正則表達式

 

2、網易財經股票數據爬蟲實戰windows

2.1 數據要求瀏覽器

  在本部分中,咱們須要採集的是海南板塊中全部股票在2012年6月29日的全部指標數據,咱們爬取的平臺是網易財經,以其中一個爲例:網絡

這是海南板塊中的一支股票的歷史數據頁面http://quotes.money.163.com/trade/lsjysj_600221.html?year=2012&season=2,而咱們須要的是海南板塊全部只股票在2012年6月29日的這十個指標(開盤價、最高價、最低價、收盤價、漲跌額、漲跌幅(%)、成交量(手)、成交金額(萬元)、振幅(%)、換手率(%)),下面,咱們分步驟分解及實現整個過程:數據結構

2.2 步驟1:獲取全部股票代碼app

  既然要利用到爬蟲來自動化、批量化地獲取數據,那咱們須要依次爬取的html地址就須要預先建立好,先來觀察網易財經歷史數據頁面的命名規則:測試

能夠看出,網易財經的歷史數據界面的命名規則爲http://quotes.money.163.com/trade/lsjysj_ 加 股票代碼 加 .html?year=年份&season=季度,所以對應咱們的數據時期要求,年份取2012,季度取2,這樣規則已經定好,惟一不肯定的是股票代碼,我從某金融軟件下載了海南板塊當前全部股票的交易數據(注意,該軟件提供的歷史交易數據維度不及網易財經網頁中提供的豐富,因此咱們纔會須要爬取網頁上的更豐富的內容),這些獨立的文件所在文件夾以下:url

咱們利用R來提取全部股票中數字代碼部分,而後保存在一個txt文件中,代碼以下:spa

rm(list=ls())
setwd('C:\\Users\\windows\\Desktop\\stock')

#獲取當前目錄下全部文件的名稱及擴展名(注意該文件夾下不要放除海南股票數據外其餘文件)
codes <- dir()

#提取每個文件名股票代碼部分
C <- c()
for(i in 1:length(codes)){
  C[i] <- substr(codes[i],3,8)
}

df <- data.frame(codes=C)

#寫出爲txt文件
write.table(df,file = 'codes.txt',row.names = F,col.names = F)

這樣咱們就獲得了保存當前全部海南板塊股票代碼的txt文件:

接下來的工做就交給Python嘍~

 

2.3 步驟2:目標網頁地址的準備

  先來用Python讀入codes.txt文件內的股票代碼:

'''設置股票代碼文件所在路近'''
path = 'C:\\Users\\windows\\Desktop\\stock\\'

'''讀入股票代碼文件,並按行分割爲列表形式'''
with open(path+'codes.txt') as c:
    code = c.readlines()

'''打印code的內容'''
print(code)

運行結果:

能夠看出,換行符\n,雙引號也被當成字符內容了,這時利用前面介紹的re.sub便可輕鬆將\n和雙引號部分刪掉:

import re

for i in range(len(code)):
    code[i] = re.sub('\\n','',code[i])
    code[i] = re.sub('"','',code[i])

print(code)

運行結果:

好了~,如今存放純股票代碼的列表已經生成,接下來須要作的就是生成咱們的全部目標網址了:

htmls = []
'''利用字符串的拼接生成全部只股票對應的目標網頁地址'''
for i in range(len(code)):
    htmls.append('http://quotes.money.163.com/trade/lsjysj_'+code[i]+'.html?year=2012&season=2')

print(htmls)
    

運行結果:

咱們用瀏覽器隨便打開一個網址試試:

 

 

2.4 步驟3:單個網址的鏈接與內容解析測試

  咱們全部目標網頁的網址都生成完畢,下面開始創建與這些網址的鏈接並進行解析,固然,由於會有不少未知的錯誤發生,所以咱們先以其中一個網址爲例先作常規的測試:

from urllib.request import urlopen
from bs4 import BeautifulSoup

'''與第一個網址創建鏈接'''
html = urlopen(htmls[0])

'''打印BeautifSoup解析後的結果'''
print(BeautifulSoup(html))

運行結果:

能夠看出,網頁內容被成功的解析了出來,接下來咱們來觀察網頁源代碼,看看咱們須要的內容藏在哪些標籤下:

很輕易的就找到了,由於這個界面比較簡單,若是遇到比較複雜的界面,能夠在界面內ctrl+F的方式定位內容,根據個人觀察,肯定了變量名稱和具體的日交易數據在標籤tr下,但其每一個數據都被包裹在一對標籤內,所以,利用findAll()來對tr定位,獲得返回值以下:

from urllib.request import urlopen
from bs4 import BeautifulSoup'''與第一個網址創建鏈接'''
html = urlopen(htmls[0])

obj = BeautifulSoup(html,'lxml')

'''利用findAll定位目標標籤及其屬性'''
obj.findAll('tr')

運行結果:

能夠看到,咱們的確獲取到包含目標內容的區塊,可是其先後都充斥着大量無關信息,所以須要使用正則表達式來精確地裁剪出咱們想要的部分,由於咱們須要的是2012-06-29的數據,而日期又是每一行數據的開頭部分,所以構造正則表達式:

2012-06-29.*2012-06-28

進行更精確地信息提取:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

'''與第一個網址創建鏈接'''
html = urlopen(htmls[0])

obj = BeautifulSoup(html,'lxml')

'''利用findAll定位目標標籤及其屬性並返回其字符形式結果'''
text = str(obj.findAll('tr'))

'''利用日期間隔爲正則表達式規則粗略提取內容'''
target = re.findall('2012-06-29.*?2012-06-28',text)[0]

print(target)

運行結果:

能夠看出,除了<>內的標籤內容外,其他的就是咱們須要提取的內容,因而乎接下來咱們繼續利用re中的功能進行細緻的提取:

'''將<>及內部標籤內容替換爲*以便下一步分割數據'''
token = re.sub('<.*?>','*',target)

'''以致少出現1次的*做爲分割依據'''
re.split('\*+',token)

運行結果:

能夠看出,該列表第2個到第11個元素即爲咱們須要的10個屬性的值,

re.split('\*+',token)[1:11]

運行結果:

 

2.5 步驟4:流水線式的全量爬蟲任務構造

  上面咱們已經針對某一個樣本基本實現了整個任務的要求過程,下面咱們將網絡數據採集的過程應用到全部股票上(這裏要注意下,由於股票代碼是當下獲取的,而其中有些股票在2012年6月29日還沒有上市,即針對其生成的網址是無效的,下面的程序中我也據此附上了對應的處理方法,請注意):

import re
from bs4 import BeautifulSoup
from urllib.request import urlopen

'''設置股票代碼文件所在路近'''
path = 'C:\\Users\\windows\\Desktop\\stock\\'

'''讀入股票代碼文件,並按行分割爲列表形式'''
with open(path+'codes.txt') as c:
    code = c.readlines()

'''獲得乾淨的股票代碼列表'''
for i in range(len(code)):
    code[i] = re.sub('\\n','',code[i])
    code[i] = re.sub('"','',code[i])


    htmls = []
'''利用字符串的拼接生成全部只股票對應的目標網頁地址'''
for i in range(len(code)):
    htmls.append('http://quotes.money.163.com/trade/lsjysj_'+code[i]+'.html?year=2012&season=2')
    
    
'''利用循環完成全部頁面的數據爬取任務'''    

'''建立保存對應股票數據的數據結構,這裏選用字典,將股票代碼做爲鍵,對應交易數據做爲值'''
data = {}
for i in range(len(code)):
    
    '''對2012年6月29日無交易數據的股票(即在爬取過程當中會出錯的網頁)進行相應的處理'''
    try:
        
        '''與每次循環歸入的目標網頁創建鏈接爬回樸素的網頁信息'''
        html = urlopen(htmls[i])
        
        '''對樸素的網頁信息進行結構化解析'''
        obj = BeautifulSoup(html,'lxml')

        '''利用findAll定位目標標籤及其屬性並返回其字符形式結果'''
        text = str(obj.findAll('tr'))

        '''利用日期間隔爲正則表達式規則粗略提取內容'''
        target = re.findall('2012-06-29.*?2012-06-28',text)[0]

        '''將<>及內部標籤內容替換爲*以便下一步分割數據'''
        token = re.sub('<.*?>','*',target)

        '''以致少出現1次的*做爲分割依據分割爲列表並返回須要的數據部分'''
        content = re.split('\*+',token)[1:11]
        
        '''將獲得的內容保存入字典中'''
        data[code[i]] = content
        
        '''當目標網頁不存在2012年6月29日的數據時,傳入字典對應的值爲錯誤解釋'''
    except Exception as e:
        data[code[i]] = '無2012年6月29日數據'

'''打印結果'''
print(data)

運行結果:

很順利的,咱們獲得了字典形式的目標數據,下面利用一些基本操做將其整理爲數據框的形式並保存爲csv文件:

import pandas as pd
import numpy as np
import re

stocks = {}

for key,value in data.items():
    if type(value) == list:
        for i in range(len(value)):
            value[i] = re.sub(',+','',value[i])
        stocks[key] = list(map(float,value))
    else:
        pass

index = []
df = [[] for i in range(10)]

for key,value in stocks.items():
    index.append(key)
    for i in range(len(value)):
        df[i].append(value[i])

D = pd.DataFrame({'股票代碼':index,
                  '開盤價':df[0],
                  '最高價':df[1],
                  '最低價':df[2],
                  '收盤價':df[3],
                  '漲跌額':df[4],
                  '漲跌幅%':df[5],
                  '成交量(手)':df[6],
                  '成交金額(萬元)':df[7],
                  '振幅':df[8],
                  '換手率(%)':df[9]})

'''設置保存路徑'''
path = 'C:\\Users\\windows\\Desktop\\stock\\'

D.to_csv(path+'海南股票數據.txt',encoding='ANSI',sep=' ',index=False)
D 

生成的txt文件以下:

 

 

  以上就是本次實戰的內容,更多爬蟲的技巧和奇妙之處,從此會在更多篇實戰中介紹,敬請期待!

相關文章
相關標籤/搜索