#coding=utf-8
'''
多线程爬取糗百的段子
分析网页:
https://www.qiushibaike.com/8hr/page/1/ 第一页
https://www.qiushibaike.com/8hr/page/2/ 第二页
https://www.qiushibaike.com/8hr/page/3/ 第三页
'''
import threading
import requests
import time
import queue
from lxml import html
import traceback
#定义线程1:从页码队列获取每页url爬取每页内容存至数据队列
class thread1(threading.Thread):
def __init__(self,pageQueue,dataQueue,threadName):
threading.Thread.__init__(self)
self.pageQueue=pageQueue #页码队列
self.dataQueue=dataQueue #每页数据队列
self.threadName=threadName #线程名称
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"
}
def run(self):
print('采集线程开始',self.threadName)
try:
#判断页码队列不为空时才开始循环
while not flag1:
pageindex=self.pageQueue.get()
url="https://www.qiushibaike.com/8hr/page/"+str(pageindex)+"/"
#请求每页糗百获取每页结果
res=requests.get(url,headers=self.headers).text
#小技巧,当请求每页时停留0.5秒,以免出现还未请求完成就开始存入队列出现异常
time.sleep(0.5)
self.dataQueue.put(res)
except Exception as e:
print(e)
traceback.print_exc(e)
print('采集线程结束',self.threadName)
#定义线程2:从数据队列爬取每条段子存至文件
class thread2(threading.Thread):
def __init__(self,dataQueue,filename,threadName):
threading.Thread.__init__(self)
self.dataQueue=dataQueue #每页数据队列
self.filename=filename #文件名
self.threadName=threadName #线程名称
def run(self):
print('解析线程开始',self.threadName)
try:
#判断数据列不为空时才开始循环
while not flag2:
data=self.dataQueue.get()
htmldata=html.etree.HTML(data)
result=htmldata.xpath('//div//a[@class="recmd-content"]')
for data in result:
data=data.text
self.filename.write(data)
self.filename.write('\n')
except Exception as e:
print(e)
traceback.print_exc(e)
print('解析线程结束',self.threadName)
#判断页码队列是否为空的标记
flag1=False
#判断数据队列是否为空的标记
flag2=False
#定义主方法
def main():
#定义页码队列
pageQueue=queue.Queue(10)
#页码队列里存入10个数当做每页的页码
for i in range(1,11):
pageQueue.put(i)
#定义数据队列
dataQueue=queue.Queue()
with open('duanzi.txt','a',encoding='utf-8') as filename:
#定义采集子线程并启动
t1=thread1(pageQueue,dataQueue,'thread-1')
t1.start()
#定义解析子线程并启动
t2=thread2(dataQueue,filename,'thread-2')
t2.start()
#主线程:判断页码队列是否为空
#当为空时pageQueue.empty()返回True,当不为空时返回False
#所以当不为空时,这个主线程会阻塞在这里
while not pageQueue.empty():
pass
#当pageQueue为空后,就退出了上述循环执行如下:
global flag1
flag1=True
#主线程同理:判断数据队列是否为空
while not dataQueue.empty():
pass
global flag2
flag2=True
'''
注:子线程t1、t2 和 主线程两个while语句是各自并行执行各自
'''
t1.join()
t2.join()
print('主线程结束,采集解析结束')
if __name__=='__main__':
main()
方式二
#coding=utf-8
#coding=utf-8
'''
多线程爬取糗百的段子
分析网页:
https://www.qiushibaike.com/8hr/page/1/ 第一页
https://www.qiushibaike.com/8hr/page/2/ 第二页
https://www.qiushibaike.com/8hr/page/3/ 第三页
'''
import threading
import requests
import time
import queue
from lxml import html
import traceback
#定义请求每页的数据,并写入到数据队列
def getPage(pageQueue,dataQueue,headers):
print('采集线程开始:{}'.format(threading.current_thread().getName()))
try:
# 判断页码队列不为空时才开始循环
while not flag1:
pageindex = pageQueue.get()
url = "https://www.qiushibaike.com/8hr/page/" + str(pageindex) + "/"
# 请求每页糗百获取每页结果
res = requests.get(url, headers=headers).text
# 小技巧,当请求每页时停留0.5秒,以免出现还未请求完成就开始存入队列出现异常
time.sleep(0.5)
dataQueue.put(res)
except Exception as e:
print(e)
traceback.print_exc(e)
print('采集线程结束:{}'.format(threading.current_thread().getName()))
#定义解析获取每页里每条段子
def getData(dataQueue,filename):
print('解析线程开始:{}'.format(threading.current_thread().getName()))
try:
# 判断数据列不为空时才开始循环
while not flag2:
data = dataQueue.get()
htmldata = html.etree.HTML(data)
result = htmldata.xpath('//div//a[@class="recmd-content"]')
for data in result:
data = data.text
filename.write(data)
filename.write('\n')
except Exception as e:
print(e)
traceback.print_exc(e)
print('解析线程结束:{}'.format(threading.current_thread().getName()))
#定义线程1:从页码队列获取每页url爬取每页内容存至数据队列
class thread1(threading.Thread):
def __init__(self,func,name,args):
#super().__init__(target=func,name=name,args=args)
# 或如下:显示调用父类构造方法
threading.Thread.__init__(self,target=func,name=name,args=args)
def run(self):
self._target(*self._args)
#定义线程2:从数据队列爬取每条段子存至文件
class thread2(threading.Thread):
def __init__(self,func,name,args):
#super().__init__(target=func,name=name,args=args)
#或如下:显示调用父类构造方法
threading.Thread.__init__(self, target=func, name=name, args=args)
def run(self):
self._target(*self._args)
#判断页码队列是否为空的标记
flag1=False
#判断数据队列是否为空的标记
flag2=False
#定义主方法
def main():
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"
}
#定义页码队列
pageQueue=queue.Queue(10)
#页码队列里存入10个数当做每页的页码
for i in range(1,11):
pageQueue.put(i)
#定义数据队列
dataQueue=queue.Queue()
with open('duanzi2.txt','a',encoding='utf-8') as filename:
#定义采集子线程并启动
t1=thread1(getPage,'thread-1',(pageQueue,dataQueue,headers))
t1.start()
#定义解析子线程并启动
t2=thread2(getData,'thread-2',(dataQueue,filename))
t2.start()
#主线程:判断页码队列是否为空
#当为空时pageQueue.empty()返回True,当不为空时返回False
#所以当不为空时,这个主线程会阻塞在这里
while not pageQueue.empty():
pass
#当pageQueue为空后,就退出了上述循环执行如下:
global flag1
flag1=True
#主线程同理:判断数据队列是否为空
while not dataQueue.empty():
pass
global flag2
flag2=True
'''
注:子线程t1、t2 和 主线程两个while语句是各自并行执行各自
'''
t1.join()
t2.join()
print('主线程结束,采集解析结束')
if __name__=='__main__':
main()