1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Python爬蟲實戰(zhàn) | 利用多線程爬取 LOL 高清壁紙

        共 4598字,需瀏覽 10分鐘

         ·

        2021-10-25 17:07

        來源:公眾號【杰哥的IT之旅】
        作者:阿拉斯加
        ID:Jake_Internet
        如需獲取本文完整代碼及 LOL 壁紙,請為本文右下角點亮在看并添加杰哥微信:Hc220088 獲取。

        一、背景介紹

        隨著移動端的普及出現(xiàn)了很多的移動 APP,應用軟件也隨之流行起來。最近看到英雄聯(lián)盟的手游上線了,感覺還行,PC 端英雄聯(lián)盟可謂是爆火的游戲,不知道移動端的英雄聯(lián)盟前途如何,那今天我們使用到多線程的方式爬取 LOL 官網(wǎng)英雄高清壁紙。

        二、頁面分析

        目標網(wǎng)站:

        https://lol.qq.com/data/info-heros.shtml#Navi

        官網(wǎng)界面如圖所示,顯而易見,一個小圖表示一個英雄,我們的目的是爬取每一個英雄的所有皮膚圖片,全部下載下來并保存到本地。

        次級頁面

        上面的頁面我們稱為主頁面,次級頁面也就是每一個英雄對應的頁面,就以黑暗之女為例,它的次級頁面如下所示:

        我們可以看到有很多的小圖,每一張小圖對應一個皮膚,通過 network 查看皮膚數(shù)據(jù)接口,如下圖所示:

        我們知道了皮膚信息是一個 json 格式的字符串進行傳輸?shù)?,那么我們只要找到每個英雄對應的 id,找到對應的 json 文件,提取需要的數(shù)據(jù)就能得到高清皮膚壁紙。

        然后這里黑暗之女的 json 的文件地址是:

        hero_one?=?'https://game.gtimg.cn/images/lol/act/img/js/hero/1.js'

        這里其實規(guī)律也非常簡單,每個英雄的皮膚數(shù)據(jù)的地址是這樣的:

        url?=?'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'.format(id)

        那么問題來了 id 的規(guī)律是怎么樣的呢?這里英雄的 id 需要在首頁查看,如下所示:

        我們可以看到兩個列表[0,99],[100,156],即 156 個英雄,但是 heroId 卻一直到了 240….,由此可見,它是有一定的變化規(guī)律的,并不是依次加一,所以要爬取全部英雄皮膚圖片,需要先拿到全部的heroId。

        三、抓取思路

        為什么使用多線程,這里解釋一下,我們在爬取圖片,視頻這種數(shù)據(jù)的時候,因為需要保存到本地,所以會使用大量的文件的讀取和寫入操作,也就是 IO 操作,試想一下如果我們進行同步請求操作;

        那么在第一次請求完成一直到文件保存到本地,才會進行第二次請求,那么這樣效率非常低下,如果使用多線程進行異步操作,效率會大大提升。

        所以必然要使用多線程或者是多進程,然后把這么多的數(shù)據(jù)隊列丟給線程池或者進程池去處理;

        在 Python 中,multiprocessing Pool 進程池,multiprocessing.dummy 非常好用。

        • multiprocessing.dummy模塊:dummy模塊是多線程;

        • multiprocessing模塊:multiprocessing是多進程;

        multiprocessing.dummy模塊與multiprocessing模塊兩者的 api 都是通用的,代碼的切換使用上比較靈活;

        我們首先在一個測試的 demo.py 文件抓取英雄 id,這里的代碼我已經(jīng)寫好了,得到一個儲存英雄 id 的列表,直接在主文件里使用即可;

        demo.py

        url?=?'https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js'
        res?=?requests.get(url,headers=headers)
        res?=?res.content.decode('utf-8')
        res_dict?=?json.loads(res)
        heros?=?res_dict["hero"]?#?156個hero信息
        idList?=?[]
        for?hero?in?heros:
        ????hero_id?=?hero["heroId"]
        ????idList.append(hero_id)
        print(idList)

        得到 idList 如下所示:

        idlist = [1,2,3,….,875,876,877] # 中間的英雄 id 這里不做展示

        構建的 url:

        page = 'http://www.bizhi88.com/s/470/{}.html'.format(i)

        這里的 i 表示 id,進行 url 的動態(tài)構建;

        那么我們定制兩個函數(shù)一個用于爬取并且解析頁面(spider),一個用于下載數(shù)據(jù) ?(download),開啟線程池,使用 for 循環(huán)構建存儲英雄皮膚 json 數(shù)據(jù)的 url,儲存在列表中,作為 url 隊列,使用 pool.map() 方法執(zhí)行 spider (爬蟲)函數(shù);

        def?map(self,?fn,?*iterables,?timeout=None,?chunksize=1):
        ????"""Returns?an?iterator?equivalent?to?map(fn,?iter)”“”
        #?這里我們的使用是:pool.map(spider,page)?# spider:爬蟲函數(shù);page:url隊列

        作用:將列表中的每個元素提取出來當作函數(shù)的參數(shù),創(chuàng)建一個個進程,放進進程池中;

        參數(shù)1:要執(zhí)行的函數(shù);

        參數(shù)2:迭代器,將迭代器中的數(shù)字作為參數(shù)依次傳入函數(shù)中;

        json數(shù)據(jù)解析

        這里我們就以黑暗之女的皮膚的 json 文件做展示進行解析,我們需要獲取的內容有?1.name,2.skin_name3.mainImg,因為我們發(fā)現(xiàn) heroName 是一樣的,所以把英雄名作為該英雄的皮膚文件夾名,這樣便于查看保存;

        item?=?{}
        item['name']?=?hero["heroName"]
        item['skin_name']?=?hero["name"]
        if?hero["mainImg"]?==?'':
        ???continue
        item['imgLink']?=?hero["mainImg"]

        有一個注意點:

        有的 mainImg 標簽是空的,所以我們需要跳過,否則如果是空的鏈接,請求時會報錯;

        四、數(shù)據(jù)采集

        導入相關第三方庫

        import?requests?#?請求
        from?multiprocessing.dummy?import?Pool?as?ThreadPool?#?并發(fā)
        import?time?#?效率
        import?os?#?文件操作
        import?json?#?解析

        頁面數(shù)據(jù)解析

        def?spider(url):
        ????res?=?requests.get(url,?headers=headers)
        ????result?=?res.content.decode('utf-8')
        ????res_dict?=?json.loads(result)

        ????skins?=?res_dict["skins"]??#?15個hero信息
        ????print(len(skins))

        ????for?index,hero?in?enumerate(skins):?#?這里使用到enumerate獲取下標,以便文件圖片命名;
        ????????item?=?{}?#?字典對象
        ????????item['name']?=?hero["heroName"]
        ????????item['skin_name']?=?hero["name"]

        ????????if?hero["mainImg"]?==?'':
        ????????????continue
        ????????item['imgLink']?=?hero["mainImg"]
        ????????print(item)

        ????????download(index+1,item)

        download 下載圖片

        def?download(index,contdict):
        ????name?=?contdict['name']
        ????path?=?"皮膚/"?+?name
        ????if?not?os.path.exists(path):
        ????????os.makedirs(path)
        ????content?=?requests.get(contdict['imgLink'],?headers=headers).content
        ????with?open('./皮膚/'?+?name?+?'/'?+?contdict['skin_name']?+?str(index)?+?'.jpg',?'wb')?as?f:
        ????????f.write(content)

        這里我們使用 OS 模塊創(chuàng)建文件夾,前面我們有說到,每個英雄的 heroName 的值是一樣的,借此創(chuàng)建文件夾并命名,方便皮膚的保存(歸類),然后就是這里圖片文件的路徑需要仔細,少一個斜杠就會報錯。

        main() 主函數(shù)

        def?main():?
        ????pool?=?ThreadPool(6)
        ????page?=?[]
        ????for?i?in?range(1,21):
        ????????newpage?=?'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'.format(i)
        ????????print(newpage)
        ????????page.append(newpage)
        ????result?=?pool.map(spider,?page)
        ????pool.close()
        ????pool.join()
        ????end?=?time.time()

        說明:

        • 在主函數(shù)里我們首選創(chuàng)建了六個線程池;

        • 通過 for 循環(huán)動態(tài)構建 20 條 url,我們小試牛刀一下,20 個英雄皮膚,如果爬取全部可以對之前的 idList 遍歷,再動態(tài)構建 url;

        • 使用 map() 函數(shù)對線程池中的 url 進行數(shù)據(jù)解析存儲操作;

        • 當線程池 close 的時候并未關閉線程池,只是會把狀態(tài)改為不可再插入元素的狀態(tài);

        五、程序運行

        if?__name__?==?'__main__':
        ????main()

        結果如下:

        當然了這里只是截取了部分圖像,總共爬取了 200+ 張圖片,總體來說還是可以。

        六、總結

        本次我們使用了多線程爬取了英雄聯(lián)盟官網(wǎng)英雄皮膚高清壁紙,因為圖片涉及到 IO 操作,我們使用并發(fā)方式進行,大大提高了程序的執(zhí)行效率。

        當然爬蟲淺嘗輒止,此次小試牛刀,爬取了 20 個英雄的皮膚圖片,感興趣的小伙伴可以把皮膚全部爬取下來,只需要改變遍歷的元素為之前的 idlist 即可。

        如需獲取本文完整代碼LOL 壁紙,請為本文右下角點亮在看添加杰哥微信:Hc220088 獲取。


        以上就是本期分享的全部內容,我是杰哥,如果你覺得這篇文章對你有點用的話,就請為本文留個言,點個贊?or?,或者轉發(fā)一下吧,我們下期不見不散!

        推薦閱讀

        HTTPS 協(xié)議到底比 HTTP 協(xié)議多些什么?

        利用 Python 實現(xiàn)多任務進程

        瀏覽 72
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            精精国产xxxx在线观看主放器 | 欧美男男互操 | 动漫黄色无码bd 久久99婷婷国产蜜臀 | 尻尻视频| 男女视频免费网站 | 大香蕉A片 | 40分钟高潮小视频 | 成 人 黄 色 免费 观 看 | 中国1级美女黄色片操逼 | 丁香六月婷婷综合 |