關於b站爬蟲的嘗試(一)


由於b站爬蟲難度較小(url地址主要通過av定位),我第一的爬蟲嘗試就選擇了b站

以下為初步的嘗試。

首先,由於初步統計,b站空視頻(已下架或者刪除)的比例大概是百分之五十(統計樣本基本在前幾年的視頻中),因此,我覺得使用簡單的迭代搜索問題不大(如果為了減少一半的搜索量寫大量爬蟲邏輯代碼比較浪費時間)我使用的是python自帶的request獲取b站頁面源代碼,然后本來想直接獲取數據。然而,開始的數據(硬幣,播放數等)並不能很容易的獲取。因為b站的數據都是通過js動態加載,直接用request只能獲得靜態頁面。不過問題不大,通過使用chrome開發者工具的監聽抓包,我找出了js文件並發現b站對外的公共接口

彈幕接口為:http://comment.bilibili.com/%s.xml %cid

視頻信息接口為:https://api.bilibili.com/x/web-interface/archive/stat?aid=%s %aid

其中,aid和cid為兩個可以從頁面源代碼中獲取的編號

以上,基本完成對b站視頻的爬蟲,當然單線程會出現速度慢的問題,目前先用

from multiprocessing.pool import Pool

解決,處理速度大概是100條/s,其中70%的時間用於request獲取頁面源碼,30%時間用於request獲取視頻信息接口的json包

之后,看了網上的爬蟲教程,部分人推薦使用seleium+PhantomJS的框架,因為PhantomJS作為無頭瀏覽器,可以直接獲取動態頁面的數據,就可以不用再用抓包和訪問api的方式獲取信息了。但是,盡管PhantomJS是無頭瀏覽器,相對的對系統的負載較小,但相對於傳統的爬蟲,功能上的損耗還是比較大的,經過測試,似乎除去了獲取json包的時間,使用seleium的獲取速度甚至比不上之前使用多線程的requests。這方面的問題可能需要再思考一下。

經統計,目前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 requests
import re
import json
import copy
from savecsv import savecsv
from savecsv import csvhead
from multiprocessing.pool import Pool
import time
from selenium import webdriver

# 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)
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 title



if __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'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM