ChenTianhao's blog

P站爬虫

P站爬虫

2017, Jan 10     陈天浩

P站中,查看一个标签中热门的图片是会员功能,但是我们可以通过爬虫实现这个功能。过程如下:

  1. 利用Cookie登陆P站(不登录只能看一个标签的前10页)
  2. 向网页发送一个get请求,获取该网页的HTML
  3. 通过BeautifulSoup和正则表达式提取HTML中每一张图片的P站id、作品名、收藏数,并将其写入SQLite中。
  4. 查询SQLite中的所有元素,按收藏数降序排序
  5. 将SQLite的查询结果写入该脚本所在目录的文件夹中

P站某种标签下的URL的格式为:’http://www.pixiv.net/search.php?word=’ + <标签名> + '&s_mode=s_tag_full&order=date_d&p=‘+<页数>,想要遍历该标签下所有的图片,只需从第1页开始往后读,直到匹配出'未找到任何相关结果'时结束循环。

完整程序:

import requests
from bs4 import BeautifulSoup
import re
import sqlite3
import time
import sys
# 在内存中创建一个临时数据库并连接
conn = sqlite3.connect(':memory:')
curs = conn.cursor()

# 新建一个表,元素包括ID,name,collNum(收藏数)
curs.execute('''CREATE TABLE pixiv
(ID INT PRIMARY KEY,
name VARCHAR(20),
collNum INT)''')
# 定义插入语句ins
ins = 'INSERT INTO pixiv VALUES(?,?,?)'
# 输入标签名
keyword = input('标签名:')

cook ='''<填自己的cookie>'''

# 将从浏览器抓取的cook整理成可以调用的格式
cookies = {}
for line in cook.split(';'):
    name, value = line.strip().split('=',1)
    cookies[name] = value

# 开始一个会话
s = requests.Session()
# 需要访问的url(不完整,后面需加上页码)
url = 'http://www.pixiv.net/search.php?word=' + keyword + '&s_mode=s_tag_full&order=date_d&p='


i = 1  # 从第一页开始爬
while True:
    # 给url加上页码,生成真实url
    rurl = url + str(i)
    # 向rurl发送一个包含cook的get请求,返回结果保存在a中
    a = s.get(rurl,cookies=cookies)
    soup = BeautifulSoup(a.text,'html.parser')
    # 选出第一个class=column-search-result的标签,保存在soup中
    soup = soup.select('.column-search-result')[0]

    # 如果汤中的文本为"未找到任何相关结果",则已经爬完所有页面,爬虫结束
    if (soup.text == "未找到任何相关结果"):
        break

    # 选出soup中所有class=image-item的标签,并遍历他们
    for link in soup.select('.image-item'):
        name = link.select('h1')[0].text  # 提取姓名

        if (link.select('.bookmark-count') != []):  # 如果存在class=bookmark-count的标签,则提取其中的收藏数
            collNum = int(link.select('.bookmark-count')[0].text)
        else:  # 如果不存在,则收藏数为0
            collNum = 0

        ID = int(re.search(r'(?<=id=)\d*',link.select('a')[0]['href']).group())  # 用正则表达式提取id
        try:  # 尝试写入数据库中
            curs.execute( ins ,(ID, name, collNum))
        except:  # 如果写入失败,则跳过
            pass

    print('第'+str(i)+'页')
    i +=1
    time.sleep(1)  # 休眠一秒(怕被封)


# 将数据库中的元素按收藏数降序排序
curs.execute('SELECT * from pixiv ORDER BY collNum DESC')

# 将结果输出至脚本所在目录的results文件夹中,文件名为<标签名>.txt
with open(sys.path[0] + keyword + '.txt', 'w', encoding='utf-8') as f:
    for line in curs.fetchall():
        f.write(line[1] + ' ' + str(line[2]) + '\n')
        f.write('http://www.pixiv.net/member_illust.php?mode=medium&illust_id=' + str(line[0]) + '\n')
        f.write('\n')


print('结果保存在' + sys.path[0] + '\\'+ keyword + '.txt' + '中')


# 关闭数据库
curs.close()
conn.close()