下载了上百个RJ后,如何根据声优或分类喜好来找到自己喜欢的作品就成了个问题,于是诞生出了这个代码

问题拆分

定位需求

查询RJ主要是在对该RJ文件夹对应网页中的标题、声优、制作社团与分类,拿到具体数据后,对数据进行查询操作。

大致方法

遍历RJ文件所在的文件夹可以使用os,提取其中的RJ号可使用re正则表达式,根据提取到的RJ号使用request模块模拟打开网站,再使用bs4对标题、声优、制作社团、分类进行提取,提取的数据保存乳本地mysql数据库中方便查询,此处使用MySQLdb库

代码

import requests
from bs4 import BeautifulSoup
import re
import os
import MySQLdb

def get_url(rj):
    url='https://www.dlsite.com'
    req_link= url + "/maniax/work/=/product_id/{}.html"
    url_rj=req_link.format(rj)
    return url_rj

def get_html(url):
    headers = {
      'Host':'www.dlsite.com',
      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'Referer':'https://www.dlsite.com/maniax/',
      'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
      'Accept-Encoding':'gzip, deflate, br',
      "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
        }
    response=requests.get(url,headers=headers)
    dl = BeautifulSoup(response.text,'html.parser')
    return dl

#第一次响应返回的html中,’h1‘标签中的标题,返回结果为标题字符串
def get_title(html):
    i=html.find('h1')
    if i:
        title=str.strip(i.get_text())
        if title == '':
            return '不明'
        else:
            return title
    else:
        return '不明'

def get_maker(html):
    i=html.find(itemprop="brand")
    if i:
        maker=str.strip(i.get_text())
        if maker == '':
            return '不明'
        else:
            return maker
    else:
        return '不明'

def get_seyuu(html):
    seyuu=html.find(id="work_outline")
    if seyuu:
        s=str.strip(seyuu.get_text())
        i=re.findall(r'[声][优][\n]+[^\n]+[\n]{2}',s)
        if i == []:
            return '不明'
        else:
            b=i[0].replace('\n','').replace('声优','').replace(' ','')
            return b
    else:
        return '不明'
def get_genre(html):
    g=html.find(class_="main_genre")
    if g:
        genre=str.strip(g.get_text())
        if genre == '':
            return '不明'
        else:
            return genre
    else:
        return '不明'
def check_rj(rj):
    host = ('localhost')
    user = ('root')
    pass_ = ('123456')
    db = ('sqlforpy')
    connect = MySQLdb.connect(host,user,pass_,db,charset='utf8')
    cursor = connect.cursor()
    sql = 'SELECT RJ FROM infor_voice'
    cursor.execute(sql)
    result = cursor.fetchall()
    rj_ = []
    n_ = 0
    for i in rj:
        r_=(i,)
        if r_ not in result:
            rj_.append(i)
            n_ += 1
        elif r_ in result:
            print('%s已存在'%i)
    print('将写入%d条信息'%n_)
    return rj_

def sql(rj,title,seyuu,maker,genre):
    host = ('localhost')
    user = ('root')
    pass_ = ('123456')
    db = ('sqlforpy')
    connect = MySQLdb.connect(host,user,pass_,db,charset='utf8')
    cursor = connect.cursor()
    sql = """insert into infor_voice(RJ,标题,声优,社团,分类)VALUES\
        ("%s","%s","%s","%s","%s")"""% (rj,title,seyuu,maker,genre)
    try:
        cursor.execute(sql)
        connect.commit()
    except:
        print('%s写入数据库出现错误!'%rj)
        connect.rollback()
    connect.close()

def get_rj(path):
    list_=[]
    for root,dirs,files in os.walk(path):
        for i in dirs:
            if i.strip().startswith('RJ'):
                rj=re.findall('[Rr][jJ][0-9]+',i)[0]
                list_.append(rj)
    return list(set((list_)))

def run_(path):
    print('查重开始')
    rj=check_rj(get_rj(path))
    print('查重结束')
    for i in rj:
        print('开始搜索%s'%i)
        url=get_url(i)
        html=get_html(url)
        sql(i,get_title(html),get_seyuu(html),get_maker(html),get_genre(html))
        print('%s保存完毕'%i)
    print('结束')

if __name__ == "__main__":
    path=r'H:\Down\For\Ad'
    run_(path)

一些笔记

本地RJ中使用了list(set(list))方法对提取到的RJ号进行去重复,在爬取前还先将数据库中原本存在的RJ号进行提取并与本地文件夹中的RJ号对比,提取非重复部分进行第二次去重,减少爬取数量。

有些RJ作品下架导致无法查询具体信息,将返回“不明”作为补充(此处代码可简化),还有RJ作品中无声优或社团信息,也将返回“不明”(此处有待优化)

写入本地数据库中,若因未知错误出现无法写入的状况将提示出错,并显示具体RJ号

一些问题

  • 下架作品查询重复,浪费时间
  • 声优信息也出现在作品描述里面,可进行替代
  • 无法反向对只有RJ号的本地文件夹进行命名操作
  • 只有标题而无RJ前缀的文件夹将无法查询
  • 后续补齐无法对本地数据库进行批量修改更新