【python】爬取某趣阁小说【欢迎大佬来喷我哪里写的不好】
本帖最后由 .Net_破解 于 2018-12-7 15:19 编辑importurllib.request as ub
import urllib.parse as parse
import time
import datetime
import re
import random
import sys
import os
import shutil
class My_urlEC(object):
"""
对url进行自己指定方式编码和解码
"""
def __init__(self,ec="utf-8"):
"""
初始化解码器
:param EC: 解码器的编码格式
"""
self.encode=ec
def Ec(self,value):
"""
将传入字符串的值进行url编码
:param value:传入的字符串
:return:
"""
value=str(value).encode(self.encode)
return parse.quote(value)
def unEc(self,value):
"""
将传入的url编码值进行解码
:param value:传入的url编码值
:return:
"""
value=str(value).encode(self.encode)
return parse.unquote(value)
def dict_urlEc(self,dict):
"""
传入的键值对的值,按照自己设定的编码格式进行转码,并生成一个get/post请求格式的字符串
功能和parse.urlencode()类似
:param value:要进行转变的字典
:return:
"""
dict_key=dict.keys()
i = 0
key_value=""
for key in dict_key:
value=self.Ec(dict)
if not i :
key_value_temp=key+"="+value
key_value+=key_value_temp
i+=1
else:
key_value_temp = "&"+key+"="+value
key_value += key_value_temp
return key_value
class biquSpider(object):
"""
笔趣阁爬虫
"""
def __init__(self,bookname,Ec):
self.book = bookname#爬取的书名
self.MyEc = My_urlEC(Ec)#转码器
self.schUrl="http://www.biquge.com.tw/modules/article/soshu.php?"#搜索的url
self.pgBaseUrl="http://www.biquge.com.tw"
self.pageUrl=[]#章节目录(一个列表里面存的是一些元组)
self.timeoutPage=[]#超时章节
self.timeout=
def get_time(self):
"""
获取以秒为单位的时间截
:return:
"""
mytime = datetime.datetime.now()+datetime.timedelta(seconds=-2*30)
return int(time.mktime(mytime.timetuple()))
def mk_request(self,url=None):
"""
获取request 根据url不同获取的request不同
:param url: 如果不传url则会返回一个搜索book的url,如果传入ulr 则去搜索对应书的章节
:return:
"""
if None == url:
self.data = {"searchkey":self.book}
url = self.schUrl+self.MyEc.dict_urlEc(self.data)
cookie = "__cdnuid=e14ba5b39182134958641bb40ee2e716; jieqiVisitTime=jieqiArticlesearchTime%3D"+str(self.get_time())
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Referer":"http://www.biquge.com.tw/16_16508/",
"Cookie":cookie,
}
return ub.Request(url,headers=headers)
def search_bk(self):
"""
搜索书并进行分析处理
:return:
"""
print("正在搜索书籍:{}------------------".format(self.book))
self.bookpath = os.path.join(os.getcwd(), self.book)
if not os.path.exists(self.bookpath):
os.mkdir(self.bookpath)
request = self.mk_request()
for i in range(0,10):
try:
response = ub.urlopen(request, timeout=self.timeout)
except:
self.timeout=self.timeout*2
if i == 9:
return -11
print("请求超时进行重新连接{}次".format(i+1))
continue
isTimeout = self.parse_sch(response)
if isTimeout==-1:
self.timeout = self.timeout * 2
if i==9:
return -1
print("请求超时进行重新连接{}次".format(i))
continue
else:
print("搜索书籍完成------------------")
return 0
def search_bkPage(self,url_temp,bg_page=None,end_page=None):
"""
搜索书的章节并进行处理
:param url_temp: 如果url_temp 为列表会进行循环遍历然后进行处理
如果不是列表 就进行简单处理
:return:
"""
self.timeoutPage=[]
if bg_page and end_page:
url_temp=url_temp
if isinstance(url_temp,list):
for url,title in url_temp:
print("正在搜索{}-----------------".format(title))
print(self.pgBaseUrl+url)
request = self.mk_request(self.pgBaseUrl+url)
try:
response = ub.urlopen(request,timeout=self.timeout)
except:
for i in range(0,10):
try:
response = ub.urlopen(request,timeout=self.timeout)
except:
self.timeout=self.timeout*2
if 9==i:
print("连接服务器超时")
sys.exit()
continue
else:
break
isTimeout = self.parse_artc(response, title)#进行处理
if -1==isTimeout:
self.timeoutPage.append((url,title))
elif isinstance(url_temp,str):
print("正在搜索章节-----------------")
request = self.mk_request(url_temp)
response = ub.urlopen(request)
self.parse_artc(response,"章节")#进行处理
if not self.timeoutPage:
print("搜索章节完成-----------------")
return
else:
if self.timeout>=10:
return
self.timeout+=1
self.timeout=self.timeout*2
print("超时的章节是:{}".format(self.timeoutPage),"自动进行重新搜索")
self.search_bkPage(self.timeoutPage)
# def get_pageUrl(self,page_url):
#
# for page in page_url:
# page = self.pgBaseUrl+page
# return page_url
def parse_sch(self,response):
"""
处理搜索的书的数据
:param response: 服务器传回的数据
:return:
"""
try:
bookhtml=response.read().decode(self.MyEc.encode)
except:
print("搜索书籍超时!")
return -1
pattern2 = re.compile(r'抱歉,搜索没有结果')
m2 = pattern2.search(bookhtml)
if m2:
m2 = pattern2.search(bookhtml)
print(m2.group())
shutil.rmtree(self.bookpath)
sys.exit()
else:
with open(os.path.join(self.bookpath,self.book+".html"),"bw") as file:
file.write(bookhtml.encode("utf-8"))
pattern = re.compile(r'<dd><a href="(.+?)">(.*?)</a></dd>')
m = pattern.findall(bookhtml)#字符串匹配 ('<dd><a href="/16_16508/9562507.html">第二千一百三十一章 我不入地狱,谁入地狱</a></dd>', '/16_16508/9562507.html', '第二千一百三十一章 我不入地狱,谁入地狱')
self.pageUrl = m
return 0
def parse_artc(self,response,title):
"""
处理搜索的章节的数据
:param response:服务器传回的数据
:return:
"""
try:
article = response.read().decode(self.MyEc.encode).encode("utf-8").decode("utf-8")
except Exception as e:
error = str(e)
if error =="timed out":
print("搜索章节{}超时".format(title))
return -1
else:
print(error)
return -2
pattern = re.compile(r' (.+?)<br />')
m = pattern.findall(article)
file2=''
for string in m:
string = string+"\n"
file2+=string
with open(os.path.join(self.bookpath,self.book +title+".txt"), "w") as file:
file.write(file2)
if __name__ == '__main__':
bookname = input("请输入书名:")
while 1:
try:
bg_page=int(input("请输入搜索的起始章节:"))
end_page=int(input("请输入搜索的结束章节:"))
except:
print('请输入阿拉伯数字')
if bg_page>0 and end_page>=bg_page:
break
print("输入的章节数错误")
spider = biquSpider(bookname,"gbk")
isTimeout = spider.search_bk()
if not isTimeout:
spider.search_bkPage(spider.pageUrl, bg_page, end_page)
else:
print("连接失败,请重新开始程序")
谢谢大佬的反馈我的开发环境是win10 + python3.5 + pycharm 没有考虑到python2.7的兼容问题 抱歉了多线程问题 会在后期的优化中加入的谢谢个位的反馈
程序出了个小bug 我传上来的时候 这个东西 ”“ ”“被转成了四个空格 这一段pattern = re.compile(r' (.+?)<br />') 应该是这样的pattern = re.compile(r' (.+?)<br />')(这段在上面代码的218行) python2.7表示无法运行.同时输入中文无效...爬的过程如果加入多线程会比较好...还有就是最好加入IP池... kof21411 发表于 2018-12-6 15:14
注释够详尽,不足的地主是:加入多线程处理会更好
大佬 多线程后期会加的 小白练手用的就没想那么复杂 支持了谢谢 注释够详尽,不足的地主是:加入多线程处理会更好 感谢楼主分享 感谢楼主分享的源码,正好在学Python 还有就是如果有重名书籍..会提示找不到书籍 我是大佬,我来喷:喷!喷!喷!{:1_921:}{:1_921:}{:1_921:} A丶Faith丶C 发表于 2018-12-6 15:26
还有就是如果有重名书籍..会提示找不到书籍
谢谢大佬反馈 小白表示万分感谢