python3+beautifulSoup4.6抓取某网站小说(四)多线程抓取
上一篇多文章,是二级目录,根目录“小说”,二级目录“作品名称”,之后就是小说文件。
本篇改造了部分代码,将目录设置为根目录->作者目录->作品目录->作品章节.txt.
但这并不是本章内容当重点,重点是使用这个爬虫程序抓取当时候,经常会因为网络丢包等原因导致程序中断,
本来想着是循环获取网站状态,然后重新发起请求,结果好像也没什么用。然后在虫师讲selenium的书中看到了多线程,正好就实验下,结果发现,速度很快,cool!
以下代码基本摘自虫师的selenium2
多线程的引用
import threading
方法调用:threading.Thread(target=music, args=('music方法参数1',music方法参数2) )
from time import sleep,ctime
import threading def music(func,loop):
for i in range(loop):
print('music',func,ctime())
sleep(2) def movie(func,loop):
for i in range(loop):
print('movie',func,ctime())
sleep(4) def testOne():
music('简单的歌', 2)
movie('两杆大烟枪', 2)
print('all end', ctime())
def testTwo():
threads = []
t1 = threading.Thread(target=music, args=('喜欢的人',2) )
threads.append(t1) t2 = threading.Thread(target=movie, args=('搏击俱乐部',2) )
threads.append(t2) t3= threading.Thread(target=music, args=('喜欢的人2', 2))
threads.append(t3) for t in threads:
t.start() for t in threads:
t.join() print('all end', ctime())
if __name__ == '__main__':
testOne()
#testTwo()
#testThree()
#threadsRun()
t.join方法用来串联线程,可以保证all end 语句在最后打印出来。
创建线程管理类
创建类名时就引入Thread:class MyThread(threading.Thread)
class MyThread(threading.Thread):
def __init__(self, func, args, name):
threading.Thread.__init__(self)
self.func = func
self.args = args
self.name = name
def run(self):
self.func(*self.args)
self:类实例,默认参数
func:调用方法名
args:参数
name:方法+".__name__"
完整代码:
class MyThread(threading.Thread):
def __init__(self, func, args, name):
threading.Thread.__init__(self)
self.func = func
self.args = args
self.name = name
def run(self):
self.func(*self.args)
def super_play(file_,time):
for i in range(3):
print('play', file_, ctime())
sleep(time)
def time(args):
pass
def testThree():
threads = []
lists = {'气球.mp3': 3, '电影.rmvb': 4, 'last.avg' : 2}
for file_, time_ in lists.items():
t = MyThread(super_play, (file_, time_), super_play.__name__)
threads.append(t)
files = range(len(lists))
for f in files:
threads[f].start()
for f in files:
threads[f].join()
print('all end', ctime())
改造小说爬虫
好了,多线程说完了,怎么调用咱们写的小说类呢,很简单
首先,改造pageOne
def readPageOneByThread(self,page,time_):
page_url = str(self.two_page_url)
new_page_url = page_url.replace("?", page)
print('第', page, '页---', new_page_url)
path = self.folder_path
self.readPageTwo(new_page_url, path)
sleep(time_)
# end readPageOneByThread ---------------------------------------
init方法中,self.two_page_url = "http://www.cuiweijuxs.com/jingpinxiaoshuo/5_?.html"
接下来,编写添加线程的方法:
def threadsRun(self):
#self.readPageOne(122)
for i in range(1,123):
page = str(i)
t = MyThread( self.readPageOneByThread, (page,2) , self.readPageOneByThread.__name__)
#t = threading.Thread(target=self.testRun, args=( str(i) ))
self.threads.append(t)
for t in self.threads:
t.start()
for t in self.threads:
t.join()
#t.join()
print('all end: %s' % ctime())
class MyThread(threading.Thread):
def __init__(self, func, args, name):
threading.Thread.__init__(self)
self.func = func
self.args = args
self.name = name
def run(self):
self.func(*self.args)
这里偷了个懒,直接写了总页数,其实也可以使用原来的pageone方法读取last的div获取页数
下面是完整代码:
# -*- coding: UTF-8 -*-
from urllib import request
from bs4 import BeautifulSoup
from time import sleep,ctime
import os
import threading
import re
import random '''
使用BeautifulSoup抓取网页
version:0.5 更新为本地缓存链接
author:yaowei
date:2018-03-23
''' class Capture(): def __init__(self):
self.index_page_url = 'http://www.cuiweijuxs.com/'
self.one_page_url = 'http://www.cuiweijuxs.com/jingpinxiaoshuo/'
self.two_page_url = "http://www.cuiweijuxs.com/jingpinxiaoshuo/5_?.html"
self.folder_path = '绯色/'
self.href_list = []
self.head = {}
self.threads = []
# 写入User Agent信息
self.head[
'User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' # end __init__ --------------------------------------- # 获取BeautifulSoup
def getSoup(self,query_url):
req = request.Request(query_url, headers=self.head)
webpage = request.urlopen(req)
html = webpage.read()
soup = BeautifulSoup(html, 'html.parser')
return soup
# soup = BeautifulSoup(html, 'html5lib') # 读取分版页面,打开分页链接
def readPageOne(self,count,time_): print('count=====',count) # 总页数
if count :
item_size = count
else :
# 读取页面
soup = self.getSoup(self.one_page_url)
last = soup.find("a", 'last')
item_size = int(last.string) print('item_size=====',item_size)
page_url = str(self.two_page_url) # 循环打开分页链接,读取分页页面
for item in range(item_size):
page = str(item + 1)
new_page_url = page_url.replace("?", page)
print('第', page, '页---', new_page_url)
path = self.folder_path
self.readPageTwo(new_page_url, path) sleep(time_)
# end readPageOne --------------------------------------- def readPageOneByThread(self,page,time_):
page_url = str(self.two_page_url)
new_page_url = page_url.replace("?", page)
print('第', page, '页---', new_page_url)
path = self.folder_path
self.readPageTwo(new_page_url, path)
sleep(time_)
# end readPageOneByThread --------------------------------------- # 读取分页页面
def readPageTwo(self, page_url, path):
soup = self.getSoup(page_url)
# first div[id="newscontent"]->div[class="l"]
con_div = soup.find('div', {'id': 'newscontent'}).find('div', {'class': 'l'})
# first div[id="newscontent"]->div[class="l"]->all spann[class="s2"]
span_list = con_div.find_all('span', {'class': 's2'}) # 遍历span
for span in span_list:
# 找到父节点下的span[class="s5"],以作者为文件夹名字
author = span.parent.find('span', {'class': 's5'}).get_text() # span[class="s2"]->a
a_href = span.find('a')
href = a_href.get('href') # 单部作品链接
folder_name = a_href.get_text() # 作品名字
print('a_href', href, '---folder_name', folder_name)
new_path = path + '/' + author + '/' + folder_name
self.createFolder(new_path) # 创建文件夹 self.readPageThree(href, new_path) # 读取单部作品 # t = threading.Thread(target=self.readPageThree, args={href, new_path})
# self.threads.append(t)
# end for # end readPage --------------------------------------- # 打开作品链接,遍历单章
def readPageThree(self, page_url, path):
soup = self.getSoup(page_url) # 作品页面
print('readPageThree--', page_url)
a_list = soup.find('div', {'id': 'list'}).find_all('a')
idx = 0 # 序号
for a_href in a_list:
idx = idx + 1
href = self.index_page_url + a_href.get('href')
file_path = path + '/' + str(idx) + '_' + a_href.get_text() + '.txt'
print('file_a_href', href, '---file_path', file_path) '''
new_path = self.isTxt(file_path)
if new_path:
print(new_path)
file_object = open('网页链接//hrefs.txt', 'w', encoding='utf-8')
file_object.write(href+','+new_path)
file_object.close()
'''
self.readPageFour(href, file_path) #self.href_list.append({'href': href, 'file_path': file_path}) # 多线程
#t = threading.Thread(target=self.readPageFour, args={href, file_path})
#t.start()
#t.join(15) # end readPageThree --------------------------------------- # 读取单章内容并写入
def readPageFour(self, page_url, path):
new_path = self.isTxt(path) # 是否存在,存在则返回'',没创建则返回合法文件名
if new_path:
soup = self.getSoup(page_url)
con_div = soup.find('div', {'id': 'content'}) # 读取文本内容
content = con_div.get_text().replace('<br/>', '\n').replace(' ', ' ')
# content = content.replace('&','').replace('amp;','').replace('rdquo;','').replace('ldquo;','')
# content = content.rstrip("& amp;rdquo;amp;& amp;ldquo;") self.writeTxt(new_path, content) # 写入文件 # end readPageFour --------------------------------------- def readPageHtml(self, page_url, path):
soup = self.getSoup(page_url)
con_div = soup.find('div', {'id': 'content'})
content = con_div.get_text().replace('<br/>', '\n').replace(' ', ' ') def createFolder(self, path):
path = path.strip()
# 去除尾部 \ 符号
path = path.rstrip("\\")
rstr = r"[\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
new_path = re.sub(rstr, "_", path) # 替换为下划线
is_exists = os.path.exists(new_path)
# 不存在则创建
if not is_exists:
os.makedirs(new_path)
print('目录:', new_path + ' create')
else:
print(new_path + ' 目录已存在') # end createFolder --------------------------------------- def isTxt(self, path):
path = path.strip()
# 去除尾部 \ 符号
path = path.rstrip("\\")
rstr = r"[\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
new_path = re.sub(rstr, "_", path) # 替换为下划线
isExists = os.path.exists(new_path)
if isExists:
print(new_path, '已存在')
return ''
else:
return new_path # end createTxt --------------------------------------- def writeTxt(self, file_name, content):
isExists = os.path.exists(file_name)
if isExists:
print(file_name, '已存在')
else:
file_object = open(file_name, 'w', encoding='utf-8')
file_object.write(content)
file_object.close() # end writeTxt ------------------------------------------ def run(self):
try:
self.readPageOne()
except BaseException as error:
print('error--', error) def runTest(self):
try:
page_url = 'http://www.cuiweijuxs.com/4_4508/'
path = '小说/runTest'
self.readPageThree(page_url, path)
except BaseException as error:
print('error--', error) def testRun(self,num,time_):
for i in range(3):
print('num=',num,ctime())
sleep(time_) def threadsRun(self): #self.readPageOne(122) for i in range(1,123):
page = str(i)
t = MyThread( self.readPageOneByThread, (page,2) , self.readPageOneByThread.__name__)
#t = threading.Thread(target=self.testRun, args=( str(i) ))
self.threads.append(t) for t in self.threads:
t.start()
for t in self.threads:
t.join()
#t.join() print('all end: %s' % ctime()) class MyThread(threading.Thread): def __init__(self, func, args, name):
threading.Thread.__init__(self)
self.func = func
self.args = args
self.name = name def run(self):
self.func(*self.args) Capture().threadsRun()
python3+beautifulSoup4.6抓取某网站小说(四)多线程抓取的更多相关文章
- python3+beautifulSoup4.6抓取某网站小说(三)网页分析,BeautifulSoup解析
本章学习内容:将网站上的小说都爬下来,存储到本地. 目标网站:www.cuiweijuxs.com 分析页面,发现一共4步:从主页进入分版打开分页列表.打开分页下所有链接.打开作品页面.打开单章内容. ...
- python3+beautifulSoup4.6抓取某网站小说(一)爬虫初探
本次学习重点: 1.使用urllib的request进行网页请求,获取当前url整版网页内容 2.对于多级抓取,先想好抓取思路,再动手 3.BeautifulSoup获取html网页中的指定内容 4. ...
- python3+beautifulSoup4.6抓取某网站小说(二)基础功能设计
本章学习内容:1.网页编码还原读取2.功能设计 stuep1:网页编码还原读取 本次抓取对象: http://www.cuiweijuxs.com/jingpinxiaoshuo/ 按照第一篇的代码来 ...
- Python多进程方式抓取基金网站内容的方法分析
因为进程也不是越多越好,我们计划分3个进程执行.意思就是 :把总共要抓取的28页分成三部分. 怎么分呢? # 初始range r = range(1,29) # 步长 step = 10 myList ...
- 网站爬取-案例三:今日头条抓取(ajax抓取JS数据)
今日头条这类的网站制作,从数据形式,CSS样式都是通过数据接口的样式来决定的,所以它的抓取方法和其他网页的抓取方法不太一样,对它的抓取需要抓取后台传来的JSON数据,先来看一下今日头条的源码结构:我们 ...
- 使用BurpSuite抓取HTTPS网站的数据包
昨天面试,技术官问到了我如何使用BurpSuite抓取https网站的数据包,一时间没能回答上来(尴尬!).因为以前https网站的数据包我都是用Fiddler抓取的,Fiddlert自动帮我们配置好 ...
- python3使用requests登录人人影视网站
python3使用requests登录人人影视网站 继续练习使用requests登录网站,人人影视有一项功能是签到功能,需要每天登录签到才能升级. 下面的代码python代码实现了使用requests ...
- 如何用python爬虫从爬取一章小说到爬取全站小说
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http ...
- webmagic爬取渲染网站
最近突然得知之后的工作有很多数据采集的任务,有朋友推荐webmagic这个项目,就上手玩了下.发现这个爬虫项目还是挺好用,爬取静态网站几乎不用自己写什么代码(当然是小型爬虫了~~|). 好了,废话少说 ...
随机推荐
- 在使用mybatis的selectFromExample时出现Invalid bound statement (not found)错误
主要原因:运行项目在构建的时候只会默认的去加载resource资源文件里面的资源,其他地方的配置资源不会加载 .故没有读取到mybatis的MapperXml映射 结构如下 ============= ...
- webpack学习(七)打包压缩图片
使用插件webpack-spritesmith生成雪碧图 1.安装webpack-spritesmith:npm install --save-dev webpack-spritesmith 2.配置 ...
- c++趣味之难以发现的bug
这些bug可能够你喝一壶的. 1.被断言(assert)包含的代码 常发生在切换到release版本时,执行结果乖乖的,最终查找结果是assert括号里的代码在release下是不执行的. 发现:跟踪 ...
- 格式化JSON数据
function formatJson(json, options) { var reg = null, formatted = '', pad = 0, PADDING = ' '; options ...
- 【日记】一次程序调优发现的同步IO写的问题,切记
众所周知,我们在写程序的时候,好习惯是在重要的代码打上日志.以便监控程序运行的性能和记录可能发生的错误. 但是,如果日志是基于同步IO文件操作,那么就必须考虑到访问总次数或并发数目. 如果总次数或并发 ...
- 网络通信 --> ZMQ安装和使用
ZMQ安装和使用 ZMQ 并不像是一个传统意义上的消息队列服务器,事实上,它也根本不是一个服务器,它更像是一个底层的网络通讯库,在 Socket API 之上做了一层封装,将网络通讯.进程通讯和线程通 ...
- 关于Mysql DATE_FORMAT() 日期格式
定义和用法 DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据. 语法 DATE_FORMAT(date,format) date 参数是合法的日期.format 规定日期/时间的输出 ...
- C++标准库string类型的使用和操作总结
string是C++标准库最重要的类型之一,string支持长度可变的字符串,其包含在string头文件中.本文摘自<C++PRIMER 第四版·特别版>和个人的一些总结. 一.声明和初始 ...
- [poj2152]fire_树形dp
fire poj-2152 题目大意:给出一颗树,给出两个相邻节点的距离,以及每个节点的接受范围,还有当前节点的代价.我们想要求出覆盖整个图的最小代价. 注释:一个点被覆盖,当且仅当该点有防火站或者这 ...
- 爬虫(scrapy第一篇)
---------------------------------------------------------------------------------------------------- ...