学习爬虫,其乐无穷!
今天给大家带来一个爬虫案例,爬取糗事百科搞笑内涵段子。
爬取糗事百科段⼦,假设⻚⾯的 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) 下的所有的商品信息。
这个大家可以试着做一做,如需爬虫视频详解,请点爬虫视频。
内容来源于网络如有侵权请私信删除