因爲b站爬蟲難度較小(url地址主要經過av定位),我第一的爬蟲嘗試就選擇了b站python
如下爲初步的嘗試。web
首先,因爲初步統計,b站空視頻(已下架或者刪除)的比例大概是百分之五十(統計樣本基本在前幾年的視頻中),所以,我以爲使用簡單的迭代搜索問題不大(若是爲了減小一半的搜索量寫大量爬蟲邏輯代碼比較浪費時間)我使用的是python自帶的request獲取b站頁面源代碼,而後原本想直接獲取數據。然而,開始的數據(硬幣,播放數等)並不能很容易的獲取。由於b站的數據都是經過js動態加載,直接用request只能得到靜態頁面。不過問題不大,經過使用chrome開發者工具的監聽抓包,我找出了js文件並發現b站對外的公共接口chrome
彈幕接口爲:http://comment.bilibili.com/%s.xml %cidjson
視頻信息接口爲:https://api.bilibili.com/x/web-interface/archive/stat?aid=%s %aidapi
其中,aid和cid爲兩個能夠從頁面源代碼中獲取的編號瀏覽器
以上,基本完成對b站視頻的爬蟲,固然單線程會出現速度慢的問題,目前先用緩存
from multiprocessing.pool import Pool多線程
解決,處理速度大概是100條/s,其中70%的時間用於request獲取頁面源碼,30%時間用於request獲取視頻信息接口的json包併發
以後,看了網上的爬蟲教程,部分人推薦使用seleium+PhantomJS的框架,由於PhantomJS做爲無頭瀏覽器,能夠直接獲取動態頁面的數據,就能夠不用再用抓包和訪問api的方式獲取信息了。可是,儘管PhantomJS是無頭瀏覽器,相對的對系統的負載較小,但相對於傳統的爬蟲,功能上的損耗仍是比較大的,通過測試,彷佛除去了獲取json包的時間,使用seleium的獲取速度甚至比不上以前使用多線程的requests。這方面的問題可能須要再思考一下。app
經統計,目前b站視頻總數大概是2000,0000個,並且還在持續增加中,若是用100/s的速度獲取,須要20,0000s,摺合55h。這個數據應該還有改進的空間。
目前想到的是兩種改進方式:
1.優化爬蟲邏輯,篩除已下架視頻(大概能夠減小一半的時間)
2.嘗試使用scrapy框架
另:目前用萬級數據測試彷佛沒有由於訪問頻率過快被禁止訪問,若是出現該狀況應該會用sleep和嘗試使用多ip地址訪問
useRequest:
# -*- coding:utf-8 -*-
import requests
import re
import json
import copy
from savecsv import savecsv
from savecsv import csvhead
from multiprocessing.pool import Pool
import time
# driver = webdriver.PhantomJS()
# driver.get("https://www.bilibili.com")
# count = 0
# dict = {}
#
# @profile
def myspider(av):
dict = {}
# global count
# global dict
url = 'https://www.bilibili.com/video/av%s/' % str(av)
resp = requests.get(url)
page = resp.text
temp = re.search(r'<div class="v-title"><h1 title="(.+?)">', page)
if temp:
# count += 1
title = re.search(r'<div class="v-title"><h1 title="(.+?)">', page).group(1)
authorkit = re.search(r'r-info.+?title="(.+?)"', page)
if authorkit:
author = authorkit.group(1)
aid = re.search(r'aid=(\d+)', page).group(1)
cid = re.search(r'cid=(\d+)', page).group(1)
print cid
if aid:
page = requests.get('https://api.bilibili.com/x/web-interface/archive/stat?aid=%s' % aid).text
info = json.loads(page)
dict[av] = copy.deepcopy(info['data'])
dict[av]['title'] = title.encode('utf-8')
dict[av]['author'] = author.encode('utf-8')
savecsv(dict, "test.csv")
# print title
# print aid
# print cid
if __name__ == "__main__":
start = time.time()
csvhead(['av','硬幣','排名','copyright','標題','分享','up主','收藏','彈幕數','回覆','aid','','最高排名','觀看數'], 'test.csv')
results = []
mypool = Pool(processes=100)
for av in xrange(10000):
results.append(mypool.apply_async(myspider, args=(av,)))
# myspider(7)
mypool.close()
mypool.join()
end = time.time()
print str(end - start)+'s'
useSeleium:
# -*- coding:utf-8 -*-import requestsimport reimport jsonimport copyfrom savecsv import savecsvfrom savecsv import csvheadfrom multiprocessing.pool import Poolimport timefrom selenium import webdriver# driver = webdriver.PhantomJS()# driver.get("https://www.bilibili.com")# count = 0# dict = {}## @profiledef myspider(av): dict = {} # global count # global dict url = 'https://www.bilibili.com/video/av%s/' % str(av) service_args = [] service_args.append('--load-images=no') ##關閉圖片加載 service_args.append('--disk-cache=yes') ##開啓緩存 service_args.append('--ignore-ssl-errors=true') ##忽略https錯誤 service_args.append('--ssl-protocol=any') driver = webdriver.PhantomJS(service_args=service_args) driver.get(url) page = driver.page_source # resp = requests.get(url) temp = re.search(r'<div class="v-title"><h1 title="(.+?)">', page) if temp: # count += 1 title = re.search(r'<div class="v-title"><h1 title="(.+?)">', page).group(1) authorkit = re.search(r'r-info.+?title="(.+?)"', page) if authorkit: author = authorkit.group(1) aid = re.search(r'aid=(\d+)', page).group(1) cid = re.search(r'cid=(\d+)', page).group(1) driver.quit() print aid print cid print titleif __name__ == "__main__": start = time.time() csvhead(['av','硬幣','排名','copyright','標題','分享','up主','收藏','彈幕數','回覆','aid','','最高排名','觀看數'], 'test.csv') results = [] # mypool = Pool(processes=100) # spiderpath() for av in xrange(10): # results.append(mypool.apply_async(myspider, args=(av,))) myspider(av) # mypool.close() # mypool.join() end = time.time() print str(end - start)+'s'