一、确定基本框架
1.确定基本分类
首先我所要编写的程序虽然简单,但因需要多次对数据库进行添加和查询,所以我将整个程序分为了两个py类:一个novelsql类用于编写对数据库操作的代码块;
其余的对网页的爬取和分析在一个novel类中。按说应该把爬取和分析分成两个类,但本程序代码简单并且不多,所以就没有分开了。
2.确定基本功能
该程序在我的想法中应具有以下的基本功能:
1.提供大的小说分类目录供选择
2.提供查询多页和特定页中的小说列表
3.提供下载特定小说的全部免费章节,并对所下载的内容进行简单的分类和调整下载文本格式(因为从网下爬下来的小说章节没有进行分页且有的语句过长,从而在记事本中查看需要使用者自己去横向的拉会很麻烦。),同时保存小说的封面图片。
基本上就这些功能,看着是不是很简单,很轻松,是不是觉得我很low?对我就是很low,你能怎么办。反正我就写了这些功能(- -!)
二 、代码编写
1.数据库操作
因为两个类中对数据库的操作要简单,所以我们先来编写对数据库的操作。首先我要明白这个类中的代码基本是供另一个类来调用的,所以我们在编写代码是应写在函数中。在py文件中导入另一个py类时,如果代码写没有写在函数中,那在加载你的py类时就会直接先将这些代码进行运行
首先我们需要导入mysql的控制
import mysql.connector
我们需要对数据库作的操作有创建表,添加,查询。
创建表的代码
def createtable(tablename,i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
sql1="DROP TABLE IF EXISTS "+tablename
sql="CREATE TABLE IF NOT EXISTS "+tablename+"(Id INT auto_increment ,num INT,t_Type VARCHAR(255),NovelName VARCHAR(25),Url VARCHAR(255), PRIMARY KEY(Id,num,NovelName))"
mycursor.execute(sql1)
mycursor.execute(sql)
mycursor.close()
mydb.close()
其中的mysql.connector.connect(host,user,passwd,database)
是对数据库创建链接,里面有着四个参数。host表示你所链接数据库的地址(这里我连接的是本地服务器,所以之是localhost);user是你访问数据库的用户名(我用的是默认用户名root);passwd是你访问数据库的密码(我没有所以用的空);database是你所访问的数据库名称。
mycursor=mydb.cursor()
这是在获取数据库游标,方便之后对sql语句的进行操作。在对sql语句进行重组时我用的是字符串拼接,这样存在一个很严重的问题——sql注入攻击。我想过取用占位符来占位但python好像不支持,如果有各位有什么好的方法请一定私信我。
向表中添加数据的代码为:
def adddata(tablename,t_type,novelname,url,i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
sql1="SELECT NovelName FROM "+tablename+" WHERE NovelName='"+novelname+"'"
mycursor.execute(sql1)
re=mycursor.fetchall()
if(re == []):
sql="INSERT INTO "+tablename+"(num,t_Type,NovelName,Url)VALUES ("+"1"+",'"+t_type+"','"+novelname+"','"+url+"') "
mycursor.execute(sql)
mydb.commit()
mycursor.close()
mydb.close()
查询的部分分两种,一种为对数据库查询表名。代码如下:
def sqlquery(i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
mycursor.execute("show tables")
return mycursor.fetchall()
另一种是对表中的数据按需查询。
def query(tablename,name,i,condition,n):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(n))
mycursor=mydb.cursor()
if i==0:
sql="SELECT "+name+" FROM "+tablename
else:
sql="SELECT "+name+" FROM "+tablename+" WHERE NovelName='"+condition+"'"
mycursor.execute(sql)
return mycursor.fetchall()
数据库的整体代码:
import mysql.connector
def database(i):
database=("feilu","feilu2")
return database[i]
def createtable(tablename,i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
sql1="DROP TABLE IF EXISTS "+tablename
sql="CREATE TABLE IF NOT EXISTS "+tablename+"(Id INT auto_increment ,num INT,t_Type VARCHAR(255),NovelName VARCHAR(25),Url VARCHAR(255), PRIMARY KEY(Id,num,NovelName))"
mycursor.execute(sql1)
mycursor.execute(sql)
mycursor.close()
mydb.close()
def adddata(tablename,t_type,novelname,url,i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
sql1="SELECT NovelName FROM "+tablename+" WHERE NovelName='"+novelname+"'"
mycursor.execute(sql1)
re=mycursor.fetchall()
if(re == []):
sql="INSERT INTO "+tablename+"(num,t_Type,NovelName,Url)VALUES ("+"1"+",'"+t_type+"','"+novelname+"','"+url+"') "
mycursor.execute(sql)
mydb.commit()
mycursor.close()
mydb.close()
def query(tablename,name,i,condition,n):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(n))
mycursor=mydb.cursor()
if i==0:
sql="SELECT "+name+" FROM "+tablename
else:
sql="SELECT "+name+" FROM "+tablename+" WHERE NovelName='"+condition+"'"
mycursor.execute(sql)
return mycursor.fetchall()
def sqlquery(i):
mydb=mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "",
database=database(i))
mycursor=mydb.cursor()
mycursor.execute("show tables")
return mycursor.fetchall()
可能会有小伙伴说我的代码怎么还有一个数据库的选择。这是因为我对两个库进行了分别的处理。要说为什么不用一个…我懒啊,用一个时会存在一些不方便。
2.网页爬取
首先是页面代码需要导入的模块有
import requests
import bs4
import urllib.request
import os
import stat
import chardet
import re
import novelsql
import lxml.html
import webbrowser
导入后我们先来看看飞卢的主页。
首先选择我们要爬取的内容,在此我用箭头标注的就是我本次程序所爬的内容。之所以不爬完,是因为太耗时间而且其他列表的爬取是一样的,所以想添加的小伙伴可以自行添加。在这里我是讲爬取的内容存到数据库,应为当时没有提前想好所以在储存时有点失误,我在项目中是直接创建以列表名为表名的表,然后再增加数据,但这样在现在看来有问题,不应该分如此多的表而是应该在表中去创建属性来区分,这样我也不需要用两个数据库。(没事我会在寒假去完善的。)
那么来获取的代码和结果如图:
因为我基本是将代码进行了封装。所以我解释一下函数的意思,具体代码后面一次会给出。第一个是根据URL去获取网页的数据。第二个是根据soup去将导航中选项与其所对应的网址存入数据库。(注意:飞卢中的有的URL并不是一个具体的网址,在存入时要进行判断,不是的要在前面加入**https://**不然无法进行访问和获取数据。)第三个是将列表中的数据,以列表名来分别存入小说名和地址,有的列表还需存入月票数与点击数。第四个是去获取刚刚存入的表名,用于向控制台输出。(因为我没写界面,所以就把控制台当做了界面进行操作。)
这个方法的完整代码。
def getmysql():
url_first = "https://b.faloo.com/"
soup = getSoup(url_first)
getbook_list(soup)
getNovels_list(soup)
reslust=novelsql.sqlquery(0)
return reslust
def getSoup(url):
htmlText = getHtmlText(url)
soup = bs4.BeautifulSoup(htmlText,'html.parser')
return soup
def getHtmlText(url):
r=requests.get(url,timeout=30)
r.raise_for_status()
r.encoding="gbk"
return r.text
def getbook_list(soup):
data =soup.find("div",{"class":"i_mm"})
tablename=data.find("div",{"id":"tab2_box1_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"c_list0"}).find_all("a")
n=0
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename=data.find("div",{"id":"tab2_box2_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"c_list0"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
data1=soup.find("div",{"class":"i2_left0"})
tablename=data1.find("div",{"id":"tab20_box1_1"}).text
novelsql.createtable(tablename,0)
data=soup.find("div",{"class":"i2_2"})
datas = data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"c_list3_1"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename=data1.find("div",{"id":"tab20_box2_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"c_list3_1"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename="".join(data1.find("div",{"class":"i2_t1"}).text.split())
novelsql.createtable(tablename,0)
datas1=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num1"})
datas2=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num_l_t"})
datas3=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num_h"})
num1=data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_l_thot"}).a.text
num2=data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_h_hot"}).text
novelname2=num1+" 票数:"+num2
novelsql.adddata(tablename,
"null",
novelname2 ,
"https:"+data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_l_thot"}).a.attrs.get("href"),
0)
list2=[]
list3=[]
list4=[]
for re in datas2:
list2.append(re.a.text)
url="https:"+re.a.attrs.get("href")
list3.append(url)
for re in datas3:
list4.append(re.text)
length=len(list2)
for i in range(length):
novelsql.adddata(tablename,
"null",
list2[i]+" 票数:"+list4[i],
list3[i],
0)
def getNovels_list(soup):
tablename="导航"
novelsql.createtable(tablename,0)
data = soup.find("div",{"class":"i_bar3"})
results=data.find_all("a")
i = 1
n = len(results)
for result in results:
novelname=result.text
if i>1 and i <n:
url="https:"+result.attrs.get("href")
else:
url = result.attrs.get("href")
novelsql.adddata(tablename,
"null",
novelname,
url,
0)
i=i+1
然后我们去获取用户选择来分别处理。因为对选择导航和列表的不同所获得的页面布局是不同的。
在此我们先来对导航来进行分析。首先当你选择后程序就会去数据库查询你所选择的数据,然后把结果返回回来。如图
然后我们就要获取用户的下一次选择,然后又有不同三种情况。
选择一的话是直接去了其他的网址如图:
对于这种我选择的是用webbrowser.open(url, new=1, autoraise=True)
来打开网页。其中new的值有不同的含义(0表示在同一个浏览器窗口中打开;1表示新的浏览器口会被打开;2表示新的浏览器tab会被打开。)
选择2的话是会进入这样格式的页面
是不是感觉很主页面很像,是的基本就不变处理画圈的右边的列表。我所做的操作是把右边的列表像之前的操作一样存起来,与之不同的是这里我是用字典来存的。(因为用数据库很烦,这个功能是我最后写的,有点急。)然后我会把列表展示给用户并根据他输入的数字去展示小说并等待用户接下来的选择。如图:
在这里就有出现不同了。就是更多和具体小说的的编号,如果是小说的编号就简单直接调用下载小说和结束的方法。但如果是更多就是这样的页面:
因为它存在很多页,所以我就去获取它的总页数,然后展示给用户并询问用户是需要查询具体的页数还是几页。这里我不得不吐槽飞卢了,看到我圈的地方了吗,对就是总页数和总小说部数。我可以很明确告诉你这书假的数据,你跳到大约160多页的时,再往后翻就会调到第一页,但它的地址却是显示后面页数的地址。
在对用户输入的数据处理时我是让用户输入时添加0来区别。如果有首位为0则表示查询从第一页到0后面数字页数的所有内容。否则就是特定页数的数据。然后获得用户选择的小说并调用下载和结束函数。对多页的输入用空格隔开,前面是具体页数,后面是小说编号。
整个对2处理的代码:
def getnovel_list(url):
soup=getSoup(url)
listnaems=soup.find_all("div",{"class":"i2_t list_t0"})
novel_list=dict()
novellists=soup.find_all("div",{"class":"list_l"})
nums=[1,3,6]
nums2=[1,3,7]
nums3=[0,1,3]
novel_list["listname"]=[listnaems[1].text.strip(),listnaems[3].text.strip(),listnaems[7].text.strip()]
mores=soup.find_all("div",{"class":"more"})
hots=soup.find_all("div",{"class":"num_l_tthot list_t2hot"})
for i in range(3):
nl=[]
urls=[]
name=dict()
nl.append(hots[nums3[i]].a.attrs.get("title"))
urls.append("https:"+hots[nums3[i]].a.attrs.get("href"))
novellistss=novellists[nums[i]].find_all("div",{"class":"num_l_tt list_t2"})
for novellist in novellistss:
nl.append(novellist.a.attrs.get("title"))
urls.append("https:"+novellist.a.attrs.get("href"))
nl.append(mores[nums2[i]].a.text)
urls.append("https:"+mores[nums2[i]].a.attrs.get("href"))
name[listnaems[nums2[i]].text.strip()+"name"]=nl
name[listnaems[nums2[i]].text.strip()+"url"]=urls
novel_list[listnaems[nums2[i]].text.strip()]=[name]
print("你所选的分类有以下新的列表:")
nus=sqlprint(novel_list["listname"],2)
number=int(input("请选择你所想查看的列表编号:"))
print(nus[number]+"的小说列表:")
urlss=novel_list[nus[number]][0][nus[number]+"url"]
nus2=sqlprint(novel_list[nus[number]][0][nus[number]+"name"],2)
number2=int(input("请输入你想预览的小说编号:"))
url=urlss[number2]
name=nus2[number2]
if name=="更多>>":
num,tablenames=getlist(url,nus[number])
if(num[0]!= "0"):
print("第{}页的小说列表如下:".format(num))
tablename=tablenames[0]
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
nums=sqlprint(myreslust,0)
index=int(input("请输入你想预览的小说编号:"))
url=novelsql.query(tablename,"url",1,nums[index],1)
url=sqlprint(url,1)
getnovel(url,nums[index])
end(url)
else:
nums=num
listdict = dict()
tablenamelist=[]
for num in range(int(nums)):
tablename=tablenames[num]
print("第{}页的小说列表如下:".format(num+1))
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
numss=sqlprint(myreslust,0)
listdict[num]=numss
tablenamelist.append(tablename)
index=input("请输入你想预览的小说页数和编号(以空格间隔):")
pages,n=index.split()
tablename=tablenamelist[eval(pages)-1]
novelname=listdict[eval(pages)-1][int(n)]
url=novelsql.query(tablename,"url",1,novelname,1)
url=sqlprint(url,1)
getnovel(url,novelname)
end(url)
else:
getnovel(url,name)
end(url)
如果选择其他的页面是这样的:
是不是很熟悉,没错就是跟选择更多的页面是一样的,不同的是这是我之前的写的所以在查询页数时,是将得到的数据以具体页数名字为表名的表中。
代码如下:
def getlist(url,listname):
soup=getSoup(url)
datas=soup.find("table",{"id":"PageListBTop"}).find_all("font",{"color":"Red"})
print("{}中一共有{}页。".format(listname,datas[1].text))
num=input("请输入你想查询的具体页数或多少页(如果查询多页请在前面加0):")
tablename=[]
if(num[0]!= "0"):
nums=num
name=getlistutil(str(nums),url)
tablename.append(name)
else:
numss=eval(num[1:])
for nums in range(numss):
nums=nums+1
name=getlistutil(str(nums),url)
tablename.append(name)
return num,tablename
接下来就是对旁边列表的操作,因为在导航,我们基本就把所有的情况处理了,所以我就下说一下下载的方法就把处理网页的代码附上作为结束。
def downnovel(url,txtname,):
soup=getSoup(url)
data=soup.find("div",{"id":"content"}).text
data1=data.split()
with open(txtname,"a",encoding="utf-8") as f:
for data in data1:
data2=fen(data)
f.write(" ")
for data in data2:
f.write(data)
f.write("\n")
之前说过为了方便阅读,我对下载的内容进行了处理,就是下面的fen方法
def fen(data):
length=len(data)
data1=[]
start=0
end=79
i=1
while length>0:
data1.append(data[start:end])
length=length-82
start=start+end
end=start+82*i
i=i+1
return data1
我用它来规定写入的每行数据最多的长度为82,多了就换行,首行要缩进2个字符。
最后整个的代码
import requests
import bs4
import urllib.request
import os
import stat
import chardet
import re
import novelsql
import lxml.html
import webbrowser
def getHtmlText(url):
r=requests.get(url,timeout=30)
r.raise_for_status()
r.encoding="gbk"
return r.text
def getNovels_list(soup):
tablename="导航"
novelsql.createtable(tablename,0)
data = soup.find("div",{"class":"i_bar3"})
results=data.find_all("a")
i = 1
n = len(results)
for result in results:
novelname=result.text
if i>1 and i <n:
url="https:"+result.attrs.get("href")
else:
url = result.attrs.get("href")
novelsql.adddata(tablename,
"null",
novelname,
url,
0)
i=i+1
def getbook_list(soup):
data =soup.find("div",{"class":"i_mm"})
tablename=data.find("div",{"id":"tab2_box1_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"c_list0"}).find_all("a")
n=0
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab2_box_1"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename=data.find("div",{"id":"tab2_box2_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"c_list0"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab2_box_2"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
data1=soup.find("div",{"class":"i2_left0"})
tablename=data1.find("div",{"id":"tab20_box1_1"}).text
novelsql.createtable(tablename,0)
data=soup.find("div",{"class":"i2_2"})
datas = data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"c_list3_1"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab20_box_1"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename=data1.find("div",{"id":"tab20_box2_1"}).text
novelsql.createtable(tablename,0)
datas = data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"c_list3_1"}).find_all("a")
for re in datas:
if n == 0:
t_type=re.attrs.get("title")
n=1
else:
novelname=re.attrs.get("title")
url=re.attrs.get("href")
novelsql.adddata(tablename,
t_type,
novelname,
"https:"+url,
0)
n=0
novelsql.adddata(tablename,
"null",
data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"more"}).a.text,
"https:"+data.find("div",{"id":"con_tab20_box_2"}).find("div",{"class":"more"}).a.attrs.get("href"),
0)
tablename="".join(data1.find("div",{"class":"i2_t1"}).text.split())
novelsql.createtable(tablename,0)
datas1=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num1"})
datas2=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num_l_t"})
datas3=data.find("div",{"id":"con_tab17_box_66"}).find_all("div",{"class":"num_h"})
num1=data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_l_thot"}).a.text
num2=data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_h_hot"}).text
novelname2=num1+" 票数:"+num2
novelsql.adddata(tablename,
"null",
novelname2 ,
"https:"+data.find("div",{"id":"con_tab17_box_66"}).find("div",{"class":"num_l_thot"}).a.attrs.get("href"),
0)
list2=[]
list3=[]
list4=[]
for re in datas2:
list2.append(re.a.text)
url="https:"+re.a.attrs.get("href")
list3.append(url)
for re in datas3:
list4.append(re.text)
length=len(list2)
for i in range(length):
novelsql.adddata(tablename,
"null",
list2[i]+" 票数:"+list4[i],
list3[i],
0)
def getSoup(url):
htmlText = getHtmlText(url)
soup = bs4.BeautifulSoup(htmlText,'html.parser')
return soup
def getmysql():
url_first = "https://b.faloo.com/"
soup = getSoup(url_first)
getbook_list(soup)
getNovels_list(soup)
reslust=novelsql.sqlquery(0)
return reslust
def sqlprint(myreslust,i):
index=0
if i == 0:
nums=[]
for (reslut,) in myreslust:
print("{}:{}".format(index,reslut))
nums.append(reslut)
index += 1
elif i == 1:
nums=""
for (reslut,) in myreslust:
nums=nums+reslut
elif i == 2:
nums=[]
for reslut in myreslust:
print("{}:{}".format(index,reslut))
nums.append(reslut)
index += 1
return nums
def getnovel(url,novelname):
soup=getSoup(url)
data=soup.find("div",{"class":"ni_3_1"})
author=data.find("div",{"class":"ni_10"}).a.text
imgname=data.find("div",{"class":"ni_5"}).img.attrs.get("alt")
imgurl=data.find("div",{"class":"ni_5"}).img.attrs.get("src")
path=str(input("你想存放的位置:"))+":"+"\\feilu\\"+author+"\\"+novelname
file_suffix = os.path.splitext(imgurl)[1]
filename = '{}{}{}{}'.format(path,os.sep,imgname,file_suffix)
if not os.path.exists(path):
os.makedirs(path)
urllib.request.urlretrieve(imgurl,filename=filename)
data=soup.find("div",{"class":"ni_list"})
datass=data.find_all("table",{"style":"margin-bottom: 10px"})
no=data.find_all("td",{"class":"td_1"})
list=[]
n=0
for i in no:
if i.b == None:
list.append(n)
n=n+1
for i in list:
data=datass[i]
datas=data.find_all("td",{"class":"td_0"})
for data1 in datas:
if data1.a == None:
break
else:
if data1.a.attrs.get("title")== None:
data2=data1.a.text.split()
name=data2[1]
else:
name=""
data2=data1.a.attrs.get("title").split(":")
names=data2[1:]
for i in names:
name=name+i
name=name.replace("/","")
txtname=path+"\\"+name+".txt"
url="https:"+data1.a.attrs.get("href")
downnovel(url,txtname)
print("小说免费部分已下载结束,存放位置为{}。".format(path))
def openurl(url):
webbrowser.open(url, new=1, autoraise=True)
def fen(data):
length=len(data)
data1=[]
start=0
end=79
i=1
while length>0:
data1.append(data[start:end])
length=length-82
start=start+end
end=start+82*i
i=i+1
return data1
def downnovel(url,txtname,):
soup=getSoup(url)
data=soup.find("div",{"id":"content"}).text
data1=data.split()
with open(txtname,"a",encoding="utf-8") as f:
for data in data1:
data2=fen(data)
f.write(" ")
for data in data2:
f.write(data)
f.write("\n")
def getlist(url,listname):
soup=getSoup(url)
datas=soup.find("table",{"id":"PageListBTop"}).find_all("font",{"color":"Red"})
print("{}中一共有{}页。".format(listname,datas[1].text))
num=input("请输入你想查询的具体页数或多少页(如果查询多页请在前面加0):")
tablename=[]
if(num[0]!= "0"):
nums=num
name=getlistutil(str(nums),url)
tablename.append(name)
else:
numss=eval(num[1:])
for nums in range(numss):
nums=nums+1
name=getlistutil(str(nums),url)
tablename.append(name)
return num,tablename
def end(url):
num=input("是否需要打开此小说网页?(y or n)")
print(num)
if(num == "y"):
openurl(url)
else:
print("谢谢使用,欢迎下次使用。")
def getlistutil(num,url):
nums=url.replace(".","#").split("#")
url=nums[0]+"."+nums[1]+"."+nums[2][:-1]+num+"."+nums[3]
soup=getSoup(url)
datas=soup.find("table",{"id":"PageListBTop"}).find_all("font",{"color":"Red"})
tablename=soup.find("div",{"class":"nav a_12b"}).h2.text+"第"+datas[0].text+"页"
novelsql.createtable(tablename,1)
datas=soup.find_all("div",{"class":"l_title a_666"})
for data in datas:
t_type=data.find_all("span")[1].a.text
novelname=data.a.text
url="https:"+data.a.attrs.get("href")
novelsql.adddata(tablename,t_type,novelname,url,1)
return tablename
def getnovel_list(url):
soup=getSoup(url)
listnaems=soup.find_all("div",{"class":"i2_t list_t0"})
novel_list=dict()
novellists=soup.find_all("div",{"class":"list_l"})
nums=[1,3,6]
nums2=[1,3,7]
nums3=[0,1,3]
novel_list["listname"]=[listnaems[1].text.strip(),listnaems[3].text.strip(),listnaems[7].text.strip()]
mores=soup.find_all("div",{"class":"more"})
hots=soup.find_all("div",{"class":"num_l_tthot list_t2hot"})
for i in range(3):
nl=[]
urls=[]
name=dict()
nl.append(hots[nums3[i]].a.attrs.get("title"))
urls.append("https:"+hots[nums3[i]].a.attrs.get("href"))
novellistss=novellists[nums[i]].find_all("div",{"class":"num_l_tt list_t2"})
for novellist in novellistss:
nl.append(novellist.a.attrs.get("title"))
urls.append("https:"+novellist.a.attrs.get("href"))
nl.append(mores[nums2[i]].a.text)
urls.append("https:"+mores[nums2[i]].a.attrs.get("href"))
name[listnaems[nums2[i]].text.strip()+"name"]=nl
name[listnaems[nums2[i]].text.strip()+"url"]=urls
novel_list[listnaems[nums2[i]].text.strip()]=[name]
print("你所选的分类有以下新的列表:")
nus=sqlprint(novel_list["listname"],2)
number=int(input("请选择你所想查看的列表编号:"))
print(nus[number]+"的小说列表:")
urlss=novel_list[nus[number]][0][nus[number]+"url"]
nus2=sqlprint(novel_list[nus[number]][0][nus[number]+"name"],2)
number2=int(input("请输入你想预览的小说编号:"))
url=urlss[number2]
name=nus2[number2]
if name=="更多>>":
num,tablenames=getlist(url,nus[number])
if(num[0]!= "0"):
print("第{}页的小说列表如下:".format(num))
tablename=tablenames[0]
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
nums=sqlprint(myreslust,0)
index=int(input("请输入你想预览的小说编号:"))
url=novelsql.query(tablename,"url",1,nums[index],1)
url=sqlprint(url,1)
getnovel(url,nums[index])
end(url)
else:
nums=num
listdict = dict()
tablenamelist=[]
for num in range(int(nums)):
tablename=tablenames[num]
print("第{}页的小说列表如下:".format(num+1))
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
numss=sqlprint(myreslust,0)
listdict[num]=numss
tablenamelist.append(tablename)
index=input("请输入你想预览的小说页数和编号(以空格间隔):")
pages,n=index.split()
tablename=tablenamelist[eval(pages)-1]
novelname=listdict[eval(pages)-1][int(n)]
url=novelsql.query(tablename,"url",1,novelname,1)
url=sqlprint(url,1)
getnovel(url,novelname)
end(url)
else:
getnovel(url,name)
end(url)
def main():
myreslust=getmysql()
print("欢迎使用小说爬取工具")
nums=sqlprint(myreslust,0)
number=int(input("请输入你想查询的编号: "))
myreslust=novelsql.query(nums[number],"novelname",0,"null",0)
print(nums[number]+"的小说列表:")
nums1=sqlprint(myreslust,0)
if number == 0:
number2=int(input("请输入你感兴趣的分类编号:"))
url=novelsql.query(nums[number],"url",1,nums1[number2],0)
url=sqlprint(url,1)
if number2<3 or number2 == 16:
openurl(url)
# print("详细内容请直接访问一下网址:{}".format(url))
elif 3<number2 <11:
getnovel_list(url)
elif number2 <16:
num,tablenames=getlist(url,nums1[number2])
if(num[0]!= "0"):
print("第{}页的小说列表如下:".format(num))
tablename=tablenames[0]
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
nums=sqlprint(myreslust,0)
index=int(input("请输入你想预览的小说编号:"))
url=novelsql.query(tablename,"url",1,nums[index],1)
url=sqlprint(url,1)
getnovel(url,nums[index])
end(url)
else:
nums=num
listdict = dict()
tablenamelist=[]
for num in range(int(nums)):
tablename=tablenames[num]
print(tablename)
print("第{}页的小说列表如下:".format(num+1))
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
numss=sqlprint(myreslust,0)
listdict[num]=numss
tablenamelist.append(tablename)
index=input("请输入你想预览的小说页数和编号(以空格间隔):")
pages,n=index.split()
tablename=tablenamelist[eval(pages)-1]
novelname=listdict[eval(pages)-1][int(n)]
url=novelsql.query(tablename,"url",1,novelname,1)
url=sqlprint(url,1)
getnovel(url,novelname)
end(url)
else:
number2=int(input("请输入你想预览的小说编号:"))
url=novelsql.query(nums[number],"url",1,nums1[number2],0)
name=nums1[number2]
url=sqlprint(url,1)
if name=="更多>>":
num,tablenames=getlist(url,nums[number])
print(tablenames)
if(num[0]!= "0"):
print("第{}页的小说列表如下:".format(num))
tablename=sqlprint(tablenames[0],1)
print(tablename)
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
nums=sqlprint(myreslust,0)
index=int(input("请输入你想预览的小说编号:"))
url=novelsql.query(tablename,"url",1,nums[index],1)
url=sqlprint(url,1)
getnovel(url,nums[index])
end(url)
else:
nums=num
listdict = dict()
tablenamelist=[]
for num in range(int(nums)):
tablename=tablenames[num]
print("第{}页的小说列表如下:".format(num+1))
myreslust=novelsql.query(tablename,"novelname",0,"null",1)
numss=sqlprint(myreslust,0)
listdict[num]=numss
tablenamelist.append(tablename)
index=input("请输入你想预览的小说页数和编号(以空格间隔):")
pages,n=index.split()
tablename=tablenamelist[eval(pages)-1]
novelname=listdict[eval(pages)-1][int(n)]
url=novelsql.query(tablename,"url",1,novelname,1)
url=sqlprint(url,1)
getnovel(url,novelname)
end(url)
else:
getnovel(url,name)
end(url)
main()