一、写在前面

  之前写的爬虫都是单机爬虫,还没有尝试过分布式爬虫,这次就是一个分布式爬虫的初体验。所谓分布式爬虫,就是要用多台电脑同时爬取数据,相比于单机爬虫,分布式爬虫的爬取速度更快,也能更好地应对IP的检测。本文介绍的是利用Redis数据库实现的分布式爬虫,Redis是一种常用的菲关系型数据库,常用数据类型包括String、Hash、Set、List和Sorted Set,重要的是Redis支持主从复制,主机能将数据同步到从机,也就能够实现读写分离。因此我们可以利用Redis的特性,借助requests模块发送请求,再解析网页和提取数据,实现一个简单的分布式爬虫。

二、基本环境

  Python版本:Python3

  Redis版本:5.0

  IDE: Pycharm

三、环境配置

由于Windows下的安装配置比较简单,所以这里只说Linux环境下安装和配置Redis(以Ubuntu为例)。

1.安装Redis

1)apt安装:

$ sudo apt-get install redis-server

2)编译安装:

$ wget http://download.redis.io/releases/redis-5.0.0.tar.gz

$ tar -xzvf redis-5.0.0.tar.gz

$ cd redis-5.0.0

$ make

$ make install

 

2.配置Redis

  首先找到redis.conf文件,然后输入命令sudo vi redis.conf,进行如下操作:

注释掉bind 127.0.0.1 # 为了远程连接,这一步还可以将bind 127.0.0.1改为bind 0.0.0.0

protected-mode yes 改为 protected-mode no

daemonized no 改为 daemonized yes

  如果6379端口被占用,还需要改一下端口号。除此之外,要远程连接还需要关闭防火墙。

chkconfig firewalld off  # 关闭防火墙

systemctl status firewalld  # 检查防火墙状态

3.远程连接Redis

  使用的命令为redis-cli -h <IP地址> -p <端口号>

  注:Windows查看IP地址用ipconfig,Linux查看IP地址用ifconfig。

四、基本思路

  这次我爬取的网站为:http://www.shu800.com/,在这个网站的首页里有五大分类,分别是性感美女、清纯可爱、明星模特、动漫美女和丝袜美腿,所以要做的第一件事就是获取这几个分类的URL。然后,对每个分类下的网页进行爬取,通过查看网页元素可以发现如下信息:

  可以很明显地看到每一页的URL都是符合一定规律的,只要获取到了尾页的URL,将其中的页数提取出来,也就能构造每一页的URL了,这就比每次去获取下一页的URL简单多了。而对于每一个图集下的图片,也是用同样的方法得到每一页图片的URL。最后要做的就是从图片网页中将图片的URL提取出来,然后下载保存到本地。

  这次分布式爬虫我使用了两台电脑,一台作为主机master,另一台作为从机slave。主机开启Redis服务,爬取每一页图片的URL,并将爬取到的URL保存到Redis的集合中,从机远程连接主机的Redis,监听Redis中是否有URL,如果有URL则提取出来进行下载图片,直至所有URL都被提取和下载。

五、主要代码

1.第一段代码是爬取每个页面里的美女图集的URL,并且把这些URL保存到数据库中,这里使用的是Redis中的集合,通过使用集合能够达到URL去重的目的,代码如下:

 def get_page(url):
     """
     爬取每个页面下的美女图集的URL
     :param url: 页面URL
     :return:
     """
     try:
         r = Redis(host="localhost", port=6379, db=1)  # 连接Redis
         time.sleep(random.random())
         res = requests.get(url, headers=headers)
         res.encoding = "utf-8"
         et = etree.HTML(res.text)
         href_list = et.xpath('/html/body/div[5]/div[1]/div[1]/div[2]/ul/li/a/@href')
         for href in href_list:
             href = "http://www.shu800.com" + href
             r.sadd("href", href)  # 保存到数据库中
     except requests.exceptions:
         headers["User-Agent"] = ua.random
         get_page(url)

2.第二段代码是从机监听Redis中是否有URL的代码,如果没有URL,等待五秒钟再运行,因为如果不稍作等待就直接运行,很容易超过Python的递归深度,所以我设置了一个等待五秒钟再运行。反之,如果有URL被添加到Redis中,就要将URL提取出来进行爬取,使用的方法是redis模块里的spop()方法,该方法会从Redis的集合中返回一个元素。需要注意的是,URL被提取出来后要先转成str。

 def get_urls():
     """
     监听Redis中是否有URL,如果没有就一直运行,如果有就提取出来进行爬取
     :return:
     """
     if b"href" in r.keys():
         while True:
             try:
                 url = r.spop("href")
                 url = url.decode("utf-8")  # unicode转str
                 print("Crawling URL: ", url)
                 get_image(url)
                 get_img_page(url)
             except:
                 if b"href" not in r.keys():  # 爬取结束,退出程序
                     break
                 else:
                     continue
     else:
         time.sleep(5)
         get_urls()

六、运行结果

  下图是在主机master上运行的截图,这里爬取到的图集总共有9633个:

  从机slave会不断地从Redis数据库中提取URL来爬取,下图是运行时的截图:

  打开文件夹看看爬下来的图片都有什么(都是这种标题,有点难顶啊...):

完整代码已上传到GitHub

最新文章

  1. Web.config配置数据库连接
  2. readline,readlines,read函数
  3. MD5加密、时间戳转换、base64算法加密、解密
  4. The requested resource is not available...
  5. 湖南附中模拟day1 收银员
  6. Vector成员为指针时要注意的问题
  7. python sort和sorted的区别以及使用方法
  8. Comparable &amp; Comparator
  9. QT宏 Q_OBJECT,explicit, QHostAddress, quint, emit
  10. eclipse开发velocity实例(初学)
  11. [ZJOI 2006]物流运输
  12. spring boot 集成 zookeeper 搭建微服务架构
  13. 数据库设计很棒的参考CDM-PDM-LDM-PowerDesigner
  14. 在CentOS上安装Python3的三种方法
  15. 【自适应波束形成】MVDR(Minimum Variance Distortionless Response )笔记
  16. 阿里云域名+github建立网站
  17. AI 学习
  18. win7右键菜单调整顺序
  19. Python设计模式 - 总览(更新中...)
  20. C#窗体操作的小技巧

热门文章

  1. 第九章 webase 分布式中间件平台快速部署
  2. 20131214-HTML基础-第二十一天
  3. Spring Boot微服务电商项目开发实战 --- 多环境部署配置、端口号统一配置及Dubbo提供者消费者实现
  4. NOIP2018普及T2暨洛谷P5016 龙虎斗
  5. SVG波浪动画
  6. oracle总结: INTERVAL DAY TO SECOND, 但却获得 NUMBER
  7. django中ORM的model对象和querryset 简单解析
  8. HPU暑期集训积分赛1
  9. 【iOS】arc4random() 产生随机数
  10. Linux ln 命令