糗事百科爬虫实例:

地址:http://www.qiushibaike.com/8hr/page/1

需求:

  1. 使用requests获取页面信息,用XPath / re 做数据提取

  2. 获取每个帖子里的用户头像链接用户姓名段子内容点赞次数评论次数

  3. 保存到 json 文件内

#qiushibaike.py

#import urllib
#import re
#import chardet import requests
from lxml import etree page = 1
url = '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)
resHtml = response.text html = etree.HTML(resHtml)
result = html.xpath('//div[contains(@id,"qiushi_tag")]') for site in result:
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].text.strip().encode('utf-8')
# 投票次数
vote = site.xpath('.//i')[0].text
#print site.xpath('.//*[@class="number"]')[0].text
# 评论信息
comments = site.xpath('.//i')[1].text print imgUrl, username, content, vote, comments except Exception, e:
print e

Queue(队列对象)

Queue是python中的标准库,可以直接import Queue引用;队列是线程间最常用的交换数据的形式

python下多线程的思考

对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列

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

  2. 包中的常用方法:

    • Queue.qsize() 返回队列的大小

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

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

    • Queue.full 与 maxsize 大小对应

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

  3. 创建一个“队列”对象

    • import Queue
    • myqueue = Queue.Queue(maxsize = 10)
  4. 将一个值放入队列中

    • myqueue.put(10)
  5. 将一个值从队列中取出

    • myqueue.get()

多线程爬虫示意图:

# -*- coding:utf-8 -*-
import requests
from lxml import etree
from Queue import Queue
import threading
import time
import json class thread_crawl(threading.Thread):
'''
抓取线程类
''' def __init__(self, threadID, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.q = q def run(self):
print "Starting " + self.threadID
self.qiushi_spider()
print "Exiting ", self.threadID def qiushi_spider(self):
# page = 1
while True:
if self.q.empty():
break
else:
page = self.q.get()
print 'qiushi_spider=', self.threadID, ',page=', str(page)
url = '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'}
# 多次尝试失败结束、防止死循环
timeout = 4
while timeout > 0:
timeout -= 1
try:
content = requests.get(url, headers=headers)
data_queue.put(content.text)
break
except Exception, e:
print 'qiushi_spider', e
if timeout < 0:
print 'timeout', url class Thread_Parser(threading.Thread):
'''
页面解析类;
''' def __init__(self, threadID, queue, lock, f):
threading.Thread.__init__(self)
self.threadID = threadID
self.queue = queue
self.lock = lock
self.f = f def run(self):
print 'starting ', self.threadID
global total, exitFlag_Parser
while not exitFlag_Parser:
try:
'''
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。
如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。
如果队列为空且block为False,队列将引发Empty异常。
'''
item = self.queue.get(False)
if not item:
pass
self.parse_data(item)
self.queue.task_done()
print 'Thread_Parser=', self.threadID, ',total=', total
except:
pass
print 'Exiting ', self.threadID def parse_data(self, item):
'''
解析网页函数
:param item: 网页内容
:return:
'''
global total
try:
html = etree.HTML(item)
result = html.xpath('//div[contains(@id,"qiushi_tag")]')
for site in result:
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 = None
try:
vote = site.xpath('.//i')[0].text
comments = site.xpath('.//i')[1].text
except:
pass
result = {
'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_ascii=False).encode('utf-8') + "\n") except Exception, e:
print 'site in result', e
except Exception, e:
print 'parse_data', e
with self.lock:
total += 1 data_queue = Queue()
exitFlag_Parser = False
lock = threading.Lock()
total = 0 def main():
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 in crawlList:
thread = thread_crawl(threadID, pageQueue)
thread.start()
crawlthreads.append(thread) #初始化解析线程parserList
parserthreads = []
parserList = ["parser-1", "parser-2", "parser-3"]
#分别启动parserList
for threadID in parserList:
thread = Thread_Parser(threadID, data_queue, lock, output)
thread.start()
parserthreads.append(thread) # 等待队列清空
while not pageQueue.empty():
pass # 等待所有线程完成
for t in crawlthreads:
t.join() while not data_queue.empty():
pass
# 通知线程是时候退出
global exitFlag_Parser
exitFlag_Parser = True for t in parserthreads:
t.join()
print "Exiting Main Thread"
with lock:
output.close() if __name__ == '__main__':
main()

  

Python爬虫开发【第1篇】【多线程爬虫及案例】的更多相关文章

  1. python自动化开发-[第二十三天]-初识爬虫

    今日概要: 1.爬汽车之家的新闻资讯 2.爬github和chouti 3.requests和beautifulsoup 4.轮询和长轮询 5.django request.POST和request. ...

  2. 【Python之路】特别篇--多线程与多进程

    并发 与 并行 的区别: 解释一:并发是在同一实体上的多个事件,并行是在不同实体上的多个事件: 解释二:并发是指两个或多个事件在同一时间间隔发生,而并行是指两个或者多个事件在同一时刻发生. 并发:就是 ...

  3. python测试开发django-51.Ajax发送post请求登录案例

    前言 我想实现一个登录功能:登录的接口是另外一个地方提供,页面上点登录按钮的时候,先访问登录接口,根据接口返回json信息判断是否登录成功,登录成功页面跳转,登录不成功,在登录首页显示失败原因 登录页 ...

  4. Python爬虫开发【第1篇】【Scrapy框架】

    Scrapy 框架介绍 Scrapy是用纯Python实现一个为了爬取网站数据.提取结构性数据而编写的应用框架. Srapy框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以 ...

  5. Python爬虫开发【第1篇】【Scrapy入门】

    Scrapy的安装介绍 Scrapy框架官方网址:http://doc.scrapy.org/en/latest Scrapy中文维护站点:http://scrapy-chs.readthedocs. ...

  6. Python爬虫开发【第1篇】【urllib2】

    1.urlopen # urllib2_urlopen.py # 导入urllib2 库 import urllib2 # 向指定的url发送请求,并返回服务器响应的类文件对象,urlopen中有da ...

  7. 爬虫开发python工具包介绍 (1)

    本文来自网易云社区 作者:王涛 本文大纲: 简易介绍今天要讲解的两个爬虫开发的python库 详细介绍 requests库及函数中的各个参数 详细介绍 tornado 中的httpcilent的应用 ...

  8. Python爬虫开发与项目实战

    Python爬虫开发与项目实战(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1MFexF6S4No_FtC5U2GCKqQ 提取码:gtz1 复制这段内容后打开百度 ...

  9. Python爬虫开发与项目实战pdf电子书|网盘链接带提取码直接提取|

    Python爬虫开发与项目实战从基本的爬虫原理开始讲解,通过介绍Pthyon编程语言与HTML基础知识引领读者入门,之后根据当前风起云涌的云计算.大数据热潮,重点讲述了云计算的相关内容及其在爬虫中的应 ...

随机推荐

  1. InnoDB 事务隔离级别

    InnoDB是一种平衡高可靠性和高性能的通用存储引擎.在MySQL数据库5.5.8版本开始,InnoDB是默认的MySQL存储引擎. InnoDB的主要优势 - 其DML操作遵循ACID,具有提交,回 ...

  2. redhat 7.x 、redhat 6.x查看硬盘UUID方法

    1.查看磁盘分区UUID: [root@rac01 ~]# blkid /dev/sdb1: UUID="6bba92c4-0b25-4cc4-9442-ca87c563720a" ...

  3. 第二讲:vcs debugging basics

    要求: 1.describe three methods of debugging verilog code using vcs 2.invoke ucli debugger(不重要) 3.debug ...

  4. ARM Linux 3.x的设备树(Device Tree)(转)

    http://blog.csdn.net/21cnbao/article/details/8457546

  5. (二十一)python 3 内置函数

    阅读目录 1.abs() 2.dict() 3.help() 4.min() 5.setattr() 6.all() 7.dir() 8.hex() 9.next() 10.slice() 11.an ...

  6. nginx.conf的完整配置说明

    #用户 用户组 user www www; #工作进程,根据硬件调整,有人说几核cpu,就配几个,我觉得可以多一点 worker_processes 5: #错误日志 error_log logs/e ...

  7. 配置工程文件dll编译后copy路径

    放到工程文件的最后面的配置节点: 下面的配置节点中生成路径换成实际的相对路径就可以了 修改:Prject.csproj 文件里面的配置节点  project配置节点里面的最后面 <Target ...

  8. Python中input()和raw_input()函数的区别

    问题:在Python2.7中使用 input() 函数会出现 “NameError: Name ”***“ is not defined 的错误 解决: 使用raw_input() 函数,在Pytho ...

  9. HDU-2647 Reward ,逆拓排。

    Reward 发工资,以前看过这题,做没做忘了(应该是没做). 很明显的拓排.但数据范围这么大,吓得我当时就不敢动手.后来找题解发现还是相当于两层循环(are you kidding me?)当时卡在 ...

  10. linux基础知识汇总

    1.如何快速回到上次操作的目录? cd - 2.如何快速回到家目录? 直接cd或者cd ~ 3.怎么回到上一级目录? cd .. 4.什么是相对路径,什么是绝对路径? 相对路径就是相对于当前目录的位置 ...