zoukankan      html  css  js  c++  java
  • 关于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'
  • 相关阅读:
    PHP配置redis支持
    redis入门——redis常用命令
    CentOS7 linux下yum安装redis以及使用
    Linux安装配置git
    Java基础88 数据库设计的三大范式
    Java基础87 MySQL数据约束
    Java基础85 MVC开发模式
    错误/异常:java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind;的解决方法
    Java基础84 javaBean规范
    Java基础83 JSP标签及jsp自定义标签(网页知识)
  • 原文地址:https://www.cnblogs.com/silencestorm/p/8487234.html
Copyright © 2011-2022 走看看