基於python的pixiv爬蟲


基於python的pixiv爬蟲

1、目標

在和朋友吹逼過程中,聊到qq群機器人,突發奇想動手做一個p站每日推薦色圖的色圖機,遂學習爬蟲。

目標:

  1. 批量下載首頁推薦色圖。
  2. 由於對qq機器人不熟,先利用flask搭鍵一個網頁色圖機。

2、流程

流程圖

3、批量下載

1、分析網頁

雖然直接進入pixiv的主頁是需要登錄的,但是進入排行榜卻不需要這個過程。

p站排行榜

通過網頁源代碼定位到圖片id

網頁源代碼

<section id="1" class="ranking-item" data-rank="1" data-rank-text="#1" data-title="無題" data-user-name="よむ" data-date="2021年05月10日 08:20" data-view-count="140513" data-rating-count="2017" data-attr="original" data-id="89739433"><div class="rank"><h1><a href="#1" class="label ui-scroll" data-hash-link="true">#1</a><i class="up sprites-up"></i></h1><p><a href="ranking.php?mode=daily&amp;date=20210510&amp;p=1&amp;ref=rn-b-1-yesterday-3#3" target="_blank">之前 #3</a></p><i class="_icon sprites-info open-info ui-modal-trigger"></i></div><div class="ranking-image-item"><a href="/artworks/89739433" class="work  _work multiple  " target="_blank"><div class="_layout-thumbnail"><img src="https://i.pximg.net/c/240x480/img-master/img/2021/05/10/08/20/13/89739433_p0_master1200.jpg" alt="" class="_thumbnail ui-scroll-view" data-filter="thumbnail-filter lazy-image" data-src="https://i.pximg.net/c/240x480/img-master/img/2021/05/10/08/20/13/89739433_p0_master1200.jpg" data-type="illust" data-id="89739433" data-tags="がんばれ同期ちゃん 予定調和 マニキュア オリジナル7500users入り 知ってる" data-user-id="6210796" style="opacity: 1;"></div><div class="page-count"><div class="icon"></div><span>4</span></div></a></div><h2><a href="/artworks/89739433" class="title" target="_blank" rel="noopener">無題</a></h2><a class="user-container ui-profile-popup" href="/users/6210796" title="よむ" data-user_id="6210796" data-user_name="よむ" data-profile_img="https://i.pximg.net/user-profile/img/2018/09/14/10/19/08/14773702_ae2f1806cc39cd6a1d91b0e451321002_50.jpg"><div class="_user-icon size-32 cover-texture ui-scroll-view" data-filter="lazy-image" data-src="https://i.pximg.net/user-profile/img/2018/09/14/10/19/08/14773702_ae2f1806cc39cd6a1d91b0e451321002_50.jpg" style="background-image: url(&quot;https://i.pximg.net/user-profile/img/2018/09/14/10/19/08/14773702_ae2f1806cc39cd6a1d91b0e451321002_50.jpg&quot;);"></div><span class="user-name">よむ</span></a></section>

可以看到這張圖片的詳細信息

data-rank="1" #排名為第一
data-user-name="よむ" #作者名為よむ
data-id="89739433" #圖片id為89739433

還有一個重要信息,是我在后期進行下載和引用時才發現的

class="page-count"><div class="icon"></div><span>4</span></div>

因為排行榜上的並非都是單張插畫,也有此類多張的漫畫,給爬蟲工作增加了許多困難。

2、分析動態頁面

在分析了這個頁面所有的內容后,發現在主頁面,只顯示了至多50張圖片的信息,但其實每日排行的圖片遠遠不止這個數量,但是pixiv並非像豆瓣或者bangumi擁有靜態的目錄,而且采取動態加載的方法,一直往下滑,則頁面一直加載。

滑了半天,得知每日圖片推薦一共有500張圖片

對於動態頁面,采取抓包查看每次動態加載的具體內容。

抓包

除了不停加載的圖片信息,抓到一條請求

https://www.pixiv.net/ranking.php?p=2&format=json

查看這個頁面

抓包內容

顯然,這是排行榜第二頁的內容,將p=2改為p=1,同樣顯示了第一頁的內容,也就是說,每次發送請求,則返回50張圖片的信息,發送十次請求,則可以獲得500張照片的信息,那么接下來的工作就簡單了。

3、熱門圖片信息獲取

抓取的網頁並非html標准格式的,不能也沒必要用bs4進行內容分析,直接用正則表達式即可。

先用request請求獲取十個頁面,並且打印出來看下是否正確。

import requests
headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
        'referer': 'https://www.pixiv.net/ranking.php?mode=daily&content=illust',
    }
for i in range(1, 11):
    url = 'https://www.pixiv.net/ranking.php?p=%d&format=json' % i
    res = requests.get(url, headers=headers)
    print(res.text)

打印結果太多了,和上圖瀏覽器中結果相同,就不做展示,正確的打印了十次請求獲取的數據。

下面通過正則表達式獲取每次請求中我們需要的內容,並打印查看

import re
id = re.findall('"illust_id":(\d+)', res.text)
for i in id:
    print(i)

ID

圖片id就嘩啦啦地出來了,檢查打印下len(id)每組都為50個,一切無誤。

同時,也將每一組圖片的張數進行獲取,方便之后的顯示、下載。

count = re.findall('"illust_page_count":"(\d+)"', res.text)

4、圖片下載

拿到了排行榜圖片的id、張數,下一步是對其進行下載。

能否進行下載一直是我很擔心的一個難點,因為有的圖片尺度過大,在未登錄時是無法直接進行訪問的。

無法訪問

先進入一張普通圖片的頁面,尋找圖片下載的地址

圖片頁面內容

<div role="presentation" class="sc-1qpw8k9-0 yjBCb"><a href="https://i.pximg.net/img-original/img/2021/05/10/08/20/13/89739433_p0.png" class="sc-1qpw8k9-3 kIEHmb gtm-expand-full-size-illust" target="_blank" rel="noopener"><img alt="#がんばれ同期ちゃん 無題 - よむ的插畫" src="https://i.pximg.net/img-master/img/2021/05/10/08/20/13/89739433_p0_master1200.jpg" 

拿到圖片下載的地址。

注意到,這個標簽的role的值為presentation,之后如果使用bs4進行查找,則可以輕松獲得下載地址。

url = 'https://www.pixiv.net/artworks/89739433'
res = requests.get(url, headers=headers)
with open('test.txt','wb') as f :
    f.write(res.text.encode('utf8'))

通過requests訪問一下試試

爬下來的內容

然而,離譜的事情就出現了,那就是通過瀏覽器直接訪問的內容和爬蟲訪問的內容是不一樣的。不過還好,就算不一樣,仍然可以拿到鏈接。

在txt文件中搜索https://i.pximg.net/img-original,找到了

"original":"https://i.pximg.net/img-original/img/2021/05/10/08/20/13/89739433_p0.png"}

通過正則,便可獲取到這個下載地址

result = re.findall(r'"original":"(.+?)"',res.text)

在下載圖片時,需要給圖片命名,分為文件名和后綴名,全部通過正則提取。

pic_name = re.findall(r'"illustTitle":"(.+?)"', res.text)[0]
extension = re.findall(r'....$', pic_url)[0]

下載圖片時,我用最簡單的方法,將原始的url的末尾刪除,for循環改變p的值,拼接上文件后綴名,從而達到下載一組多張圖片的功能

pic_url = re.sub('.....$','',pic_url)
# 下載圖片
for i in range(0,int(count)):
    url = pic_url+str(i)+extension
    print(url)
    pic = requests.get(url, headers=headers)
    with open('%s%d%s' % (pic_name, i, extension), 'wb') as f:
        f.write(pic.content)

最后,將之前所有的代碼整合,構造一個函數,輸入圖片id和圖片張數,自動下載。

def download(id, count):
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
        'referer': 'https://www.pixiv.net/ranking.php?mode=daily&content=illust',
    }

    url = 'https://www.pixiv.net/artworks/%d' % id
    res = requests.get(url, headers=headers)
    pic_url = re.findall(r'"original":"(.+?)"', res.text)[0]
    pic_name = re.findall(r'"illustTitle":"(.+?)"', res.text)[0]
    # 獲取后綴
    extension = re.findall(r'....$', pic_url)[0]
    pic_url = re.sub('.....$','',pic_url)
    # 下載圖片
    for i in range(0,int(count)):
        url = pic_url+str(i)+extension
        print(url)
        pic = requests.get(url, headers=headers)
        with open('%s%d%s'% (pic_name, i, extension), 'wb') as f:
            f.write(pic.content)

5、debug

獲取到了圖片的id和張數,並且構造了輸入id和張數就能自動執行腳本的函數,將兩者稍作整合,結果在運行時報錯:

OSError: [Errno 22] Invalid argument: './ex/電車で寄りかかられたOLと寄りかかってきた居眠り(?)JK1.jpg'

顯然,文件命名不能包含'?',於是添加正則去除這些符號

if re.search('[\\\ \/ \* \? \" \: \< \> \|]', pic_name) != None:
  pic_name = re.sub('[\\\ \/ \* \? \" \: \< \> \|]', '', pic_name)

之后運行正常

6、總代碼

#-*— codeing = utf-8 -*-
import requests
import re
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
    'referer': 'https://www.pixiv.net/ranking.php?mode=daily&content=illust',
}
def download(id, count):
    url = 'https://www.pixiv.net/artworks/%d' % id
    res = requests.get(url, headers=headers)
    pic_url = re.findall(r'"original":"(.+?)"', res.text)[0]
    pic_name = re.findall(r'"illustTitle":"(.+?)"', res.text)[0]
    # 獲取后綴
    extension = re.findall(r'....$', pic_url)[0]
    pic_url = re.sub('.....$','',pic_url)
    if re.search('[\\\ \/ \* \? \" \: \< \> \|]', pic_name) != None:
        pic_name = re.sub('[\\\ \/ \* \? \" \: \< \> \|]', '', pic_name)
    # 下載圖片
    for i in range(0,int(count)):
        url = pic_url+str(i)+extension
        print('正在下載id為:%d的第%d張圖片'%(id,i+1),end='   ')
        pic = requests.get(url, headers=headers)
        with open('./ex/%s%d%s' % (pic_name, i+1, extension), 'wb') as f:
            f.write(pic.content)
            print('下載成功', end='\n')
def bot():
    id = []
    count = []
    for i in range(1, 2):
        url = 'https://www.pixiv.net/ranking.php?p=%d&format=json' % i
        res = requests.get(url, headers=headers)
        id = id + re.findall('"illust_id":(\d+)', res.text)
        count = count + re.findall('"illust_page_count":"(\d+)"', res.text)
    if len(id) == len(count):
        for i in range(0,len(id)):
            download(int(id[i]),int(count[i]))
bot()

4、網頁搭鍵

1、思路

如果要將所有圖片下載至服務器,且不說我使用的阿里雲無法訪問p站,占用空間、下載花費時間,都是問題。而p站的圖片的下載地址鏈接並沒有辦法直接顯示圖片,固選擇第三方代理來實現在網頁中顯示p站圖片的功能。

使用的代理網站是

pixiv.cat

雖然在國內直接訪問速度也並不理想,但是可以直接通過鏈接在網頁中顯示圖片。

重新寫一個爬蟲,功能是把所有每日推薦圖片的id存到一個txt文件中,方便我們在服務器上直接調用。值得注意的是,如果這組圖片不止一張,就在圖片id后加一個'-1',這樣代理網站才能正常工作(代理網站規則請自行前往查看)

2、爬蟲代碼

for i in range(1, 11):
    url = 'https://www.pixiv.net/ranking.php?p=%d&format=json' % i
    res = requests.get(url, headers=headers)
    illust_id = re.findall('"illust_id":(\d+?),', res.text)
    illust_page_count = re.findall('"illust_page_count":"(\d+?)"', res.text)
    len_ = len(illust_id)
    i = 0
    if len_ != 0:
        while i < len_:
            with open('id.txt','a') as f:
                if illust_page_count[i] == '1':
                    f.write(illust_id[i])
                    f.write('\n')
                else :
                    f.write(illust_id[i])
                    f.write('-1')
                    f.write('\n')
            i = i+1
    else:
        pass

3、flask代碼

from flask import Flask,render_template
import random

app = Flask(__name__)
list_ = []
with open('id.txt')as id_list:
    for line in id_list:
        line = line.strip('\n')
        list_.append(line)

len = len(list_)
ran = list_[random.randint(1,len)]

@app.route('/')
def index():
    ran = list_[random.randint(1, len)]
    return render_template("index.html",pic=ran)

if __name__ == '__main__':
    app.run(app.run(host='0.0.0.0', port=8001, debug=True))

大致思路是讀取txt文件,隨機取得一張圖片的id,並傳遞給前端

4、前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>色圖機</title>
<html lang="en">
<head>
    <meta charset="UTF-8">

</head>
<script>
        function handle() {
            document.getElementById('myImage').src='https://pixiv.cat/'+'{{ pic }}'+'.jpg';
        }
    </script>

<body >
    <h1 style="text-align: center;">色圖機</h1>
    <div style="text-align: center;">
    <img height="500" id= "myImage" src='https://pixiv.cat/{{ pic }}.jpg'/>
    </div>
    <h2 style="text-align: center;">p站id為:{{pic}}</h2>
    <h2 style="text-align: center;">刷新頁面以刷新色圖</h2>
    <footer style="text-align: center;">
        圖片來源為pixiv每日推薦,本網站僅做學習,圖片內容與本人無關
        <br>power by huigugu
        <br>To dear じじ
    </footer>
</body>
</html>
</head>
</html>

5、總結

  1. 對於基礎的爬蟲,難點在分析網頁內容。
  2. 通過瀏覽器訪問到的和通過爬蟲訪問到的不盡相同。
  3. 看色圖久了會感覺枯燥無味。

6、參考資料

  1. b站爬蟲教學視頻 http://www.bilibili.com/video/BV12E411A7ZQ
  2. CSDN相似爬蟲項目(在其基礎上解決了一組多張圖片的問題) https://blog.csdn.net/weixin_45826022/article/details/109406389


免責聲明!

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



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