python多线程爬取段子_Python爬虫实例-多线程爬虫糗事百科搞笑内涵段子

学习爬虫,其乐无穷!

今天给大家带来一个爬虫案例,爬取糗事百科搞笑内涵段子。

爬取糗事百科段⼦,假设⻚⾯的 URL 是:http://www.qiushibaike.com/8hr/page/1

一、爬取要求:

使⽤requests 获取⻚⾯信息,⽤XPath / re 做数据提取。

获取每个帖⼦⾥的 ⽤户头像链接 、 ⽤户姓名 、 段⼦内容 、 点赞次数 和 评论次数。

保存到 json ⽂件内。

二、先来看看单线程案例

参考代码:

#qiushibaike.py#import urllib#import re#import chardet

importrequestsfrom lxml importetree

page= 1url= 'http://www.qiushibaike.com/8hr/page/' +str(page)

headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit

/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36','Accept-Language': 'zh-CN,zh;q=0.8'}try:

response= requests.get(url, headers=headers)167resHtml=response.text

html=etree.HTML(resHtml)

result= html.xpath('//div[contains(@id,"qiushi_tag")]')for site inresult:

item={}

imgUrl= site.xpath('./div/a/img/@src')[0].encode('utf-8')

username= site.xpath('./div/a/@title')[0].encode('utf-8')#username = site.xpath('.//h2')[0].text

content = site.xpath('.//div[@class="content"]/span')[0].te

xt.strip().encode('utf-8') #投票次数

vote = site.xpath('.//i')[0].text#print site.xpath('.//*[@class="number"]')[0].text#评论信息

comments = site.xpath('.//i')[1].textprintimgUrl, username, content, vote, commentsexceptException, e:print e

演示效果:

三、多线程案例

Queue(队列对象):

Queue 是 python 中的标准库,可以直接 import Queue 引⽤;队列是线程间最常⽤的交换数据的形式python 下多线程的思考 对于资源,加锁是个重要的环节。因为 python 原⽣的list,dict 等,都是 not thread safe 的。⽽Queue,是线程安全的,因此在满⾜使⽤条件下,建议使⽤队列。

初始化: class Queue.Queue(maxsize) FIFO 先进先出

包中的常⽤⽅法:

Queue.qsize() 返回队列的⼤⼩

Queue.empty() 如果队列为空,返回 True,反之 False

Queue.full() 如果队列满了,返回 True,反之 False

Queue.full 与 maxsize ⼤⼩对应

Queue.get([block[, timeout]])获取队列,timeout 等待时间

创建⼀个“队列”对象import Queue myqueue = Queue.Queue(maxsize = 10)

将⼀个值放⼊队列中myqueue.put(10)

将⼀个值从队列中取出myqueue.get()

多线程示意图:

如需要python爬虫全套完整的入门到项目实战视频教程,请点:爬虫视频教程。

参考代码:

#-*- coding:utf-8 -*-

importrequestsfrom lxml importetreefrom Queue importQueueimportthreadingimporttimeimportjsonclassthread_crawl(threading.Thread):'''抓取线程类'''

definit (self, threadID, q):

threading.Thread. init (self)

self.threadID=threadID

self.q=qdefrun(self):print "Starting" +self.threadID

self.qiushi_spider()print "Exiting", self.threadIDdef qiushi_spider(self): #page = 1

whileTrue:ifself.q.empty():break

else:

page=self.q.get()print 'qiushi_spider=', self.threadID, ',page=', str(page)

url= 'http://www.qiushibaike.com/hot/page/' +str(

page)+ '/'headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WO

W64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116Sa

fari/537.36','Accept-Language': 'zh-CN,zh;q=0.8'} #多次尝试失败结束、防⽌死循环

timeout = 4

while timeout >0:

timeout-= 1

try:

content= requests.get(url, headers=headers

)

data_queue.put(content.text)break

exceptException, e:print 'qiushi_spider', eif timeout <0:print 'timeout', urlclassThread_Parser(threading.Thread):'''⻚⾯解析类;'''

definit (self, threadID, queue, lock, f):

threading.Thread. init (self)

self.threadID=threadID

self.queue=queue

self.lock=lock

self.f=fdefrun(self):print 'starting', self.threadIDglobaltotal, exitFlag_Parserwhile notexitFlag_Parser:try:'''调⽤队列对象的 get()⽅法从队头删除并返回⼀个项⽬。可选参 数 为 block,默认为 True。

如果队列为空且 block 为 True,get()就使调⽤线程暂停,直⾄

有项⽬可⽤。

otal

如果队列为空且 block 为 False,队列将引发 Empty 异常。'''item=self.queue.get(False)if notitem:passself.parse_data(item)

self.queue.task_done()print 'Thread_Parser=', self.threadID, ',total=', texcept:pass

print 'Exiting', self.threadIDdefparse_data(self, item):'''解析⽹⻚函数

:param item: ⽹⻚内容

:return:'''

globaltotaltry:

html=etree.HTML(item)

result= html.xpath('//div[contains(@id,"qiushi_tag")]')for site inresult:try:

imgUrl= site.xpath('.//img/@src')[0]

title= site.xpath('.//h2')[0].text

content= site.xpath('.//div[@class="content"]/

span')[0].text.strip()

vote =None

comments=Nonetry:

vote= site.xpath('.//i')[0].text

comments= site.xpath('.//i')[1].textexcept:passresult={'imgUrl': imgUrl,'title': title,'content': content,'vote': vote,'comments': comments,

}

with self.lock:#print 'write %s' % json.dumps(result)

self.f.write(json.dumps(result, ensure_asci

i=False).encode('utf-8') + "n")exceptException, e:print 'site in result', eexceptException, e:print 'parse_data', e

with self.lock:

total+= 1data_queue=Queue()

exitFlag_Parser=False

lock=threading.Lock()

total=0defmain():

output= open('qiushibaike.json', 'a') #初始化⽹⻚⻚码 page 从 1-10 个⻚⾯

pageQueue = Queue(50)for page in range(1, 11):

pageQueue.put(page)#初始化采集线程

crawlthreads =[]

crawlList= ["crawl-1", "crawl-2", "crawl-3"]for threadID incrawlList:

thread=thread_crawl(threadID, pageQueue)

thread.start()

crawlthreads.append(thread)#初始化解析线程 parserList

parserthreads =[]

parserList= ["parser-1", "parser-2", "parser-3"] #分别启动 parserList

for threadID inparserList:

thread=Thread_Parser(threadID, data_queue, lock, output)

thread.start()

parserthreads.append(thread)#等待队列清空

while notpageQueue.empty():pass

#等待所有线程完成

for t incrawlthreads:

t.join()while notdata_queue.empty():pass

#通知线程是时候退出

globalexitFlag_Parser

exitFlag_Parser=Truefor t inparserthreads:

t.join()print "Exiting Main Thread"with lock:

output.close()if name == 'main':

main()

四、课后作业

1、爬取笔趣⽹某部⼩说的所有页面。

2、国家⻝品药品监督管理总局:http://app1.sfda.gov.cn 采集分类 国产药品商品名(6994) 下的所有的商品信息。

这个大家可以试着做一做,如需爬虫视频详解,请点爬虫视频。

内容来源于网络如有侵权请私信删除

你可能感兴趣的:(python多线程爬取段子)