python爬虫学习:分布式抓取
前面的文章都是基于在单机操作,正常情况下,一台机器无论配置多么高,线程开得再多,也总会有一个上限,或者说成本过于巨大。因此,本文将提及分布式的爬虫,让爬虫的效率提高得更快。
构建分布式爬虫首先需要有多台机器,作者利用 VMware 安装了 2 台虚拟机,安装的教程请看 VMwareWorkstation下安装Linux。安装的 2台机器为 CentOS6.6 ,命名为 device1 、device2 ,master 为 device1 , 初始密码为 1111 。
安装好了后,用 Xshell5 打开虚拟机的命令行,打开方式如下:
安装 Xshell5 ,可以在本网站首页 中的网盘中下载安装
在虚拟机中右键打开控制台,输入 ifconfig 得到机器的 ip 地址
在 Xshell5 中新建连接,名称为 device1 、 device2 ,主机为 ip 地址,使用 用户身份验证登陆 ,用户名是 root , 密码是 1111
设备对应关系为:device1-192.168.230.218 、 device2-192.168.230.223 。首先需要给虚拟机安装 redis 集群,安装集群需要 ruby 环境,每台机器执行如下命令:
yum -y install zlib ruby rubygems
这里我用两台服务器,6 个节点,互为主从,即 3 个主节点 3 个从节点 ,我的两台机器的 ip 地址为 192.168.230.218 和 192.168.230.223 ,分别给两台机器安装 redis ,在 /usr/local/ 目录下操作,两台机器都进行如下操作:
cd /usr/local/
wget http://download.redis.io/releases/redis-3.2.0.tar.gz
tar -zxvf redis-3.2.0.tar.gz
mkdir redis
cd redis-3.2.0
make install PREFIX=/usr/local/redis
将集群工具复制到 /usr/local/redis/bin 下,创建目录和配置文件:
cp /usr/local/redis-3.2.0/src/redis-trib.rb /usr/local/redis/bin/
mkdir -p /usr/local/redis/{conf,data,logs}
cd /usr/local/redis
cp /usr/local/redis-3.2.0/redis.conf ./conf/redis-6380.conf
更改配置文件 redis-6380.conf 为:
# 基本配置
daemonize yes
pidfile /usr/local/redis/data/redis-6380.pid
port 6380
bind 192.168.230.218
unixsocket /usr/local/redis/data/redis-6380.sock
unixsocketperm 700
timeout 300
loglevel verbose
logfile /usr/local/redis/logs/redis-6380.log
databases 16
dbfilename dump-6380.rdb
dir /usr/local/redis/data/
# aof持久化
appendonly yes
appendfilename appendonly-6380.aof
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 80-100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
# 集群配置
cluster-enabled yes
cluster-config-file /usr/local/redis/data/nodes-6380.conf
cluster-node-timeout 5000
启动 redis :
cd /usr/local/redis/
./bin/redis-server ./conf/redis-6380.conf
./bin/redis-server ./conf/redis-6381.conf
./bin/redis-server ./conf/redis-6382.conf
开始启动集群,注意两台机器的 redis 都要启动,都启动后执行如下命令:
cd /usr.local/
gem install redis
./bin/redis-trib.rb create --replicas 1 192.168.230.218:6380 192.168.230.218:6381 192.168.230.218:6382 192.168.230.223:6383 192.168.230.223:6384 192.168.230.223:6385
如果出现:
Could not connect to Redis at 192.168.230.223:6380: No route to host
则说明 192.168.230.223 的防火墙或者端口没开,简单一点的操作在 192.168.230.223 中执行:
iptables -A INPUT -p TCP --dport 6380 -j REJECT
iptables -A INPUT -p TCP --dport 6381 -j REJECT
iptables -A INPUT -p TCP --dport 6382 -j REJECT
sudo iptables -F
如果创建 Node 失败,即报出错误:
[ERR] Node 192.168.230.218:6380 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
则依次对每台机器每个端口都执行如下命令:
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6383
flushdb
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6384
flushdb
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6385
flushdb
并且将 data 里面的文件删除:
cd /usr/local/redis/data/
rm -rf ./*
最后重启全部的节点。其实启动和关闭可以写两个 shell 脚本执行,启动脚本 start.sh:
cd /usr/local/redis/
./bin/redis-server ./conf/redis-6380.conf
./bin/redis-server ./conf/redis-6381.conf
./bin/redis-server ./conf/redis-6382.conf
关闭脚本 end.sh :
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6383 shutdown
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6384 shutdown
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6385 shutdown
集群测试是否安装成功,两台机器都启动 redis 后,在 device1 中执行:
/usr/local/redis/bin/redis-cli -h 192.168.230.223 -p 6383
出现如下对话框:
则说明两台机器已经可以相互通讯了,防火墙已经关闭。
如果在执行了:
./bin/redis-trib.rb create --replicas 1 192.168.230.218:6380 192.168.230.218:6381 192.168.230.218:6382 192.168.230.223:6383 192.168.230.223:6384 192.168.230.223:6385
屏幕出现如下字样:
则说明 redis 集群连接成功,下面试一下通讯。在 192.168.230.218 输入以下命令进入集群模式:
/usr/local/redis/bin/redis-cli -c -h 192.168.230.223 -p 6385
192.168.230.223:6385> set ttyb baige
-> Redirected to slot [12905] located at 192.168.230.223:6384
OK
在 192.168.230.223 查询是否收到了命令:
/usr/local/redis/bin/redis-cli -c -h 192.168.230.218 -p 6382
192.168.230.218:6382> get ttyb
-> Redirected to slot [12905] located at 192.168.230.223:6384
"baige"
redis 集群搭建完毕!!!
现在需要在 Linux 系统里面安装相对应的 python 版本到系统里面,安装的教程请看 Linux下python2和python3共存。
安装完 python 后,可以先在本地写好脚本,再上传到虚拟机里面,推荐使用 Xshell5 和 Xftp5 。在本机先下载一个 redis 软件,这个可以在我的网盘里面弄找到百度网盘,
如果机器重启了无法连接,记得去虚拟机中关闭防火墙:
service iptables start / stop
iptables: Setting chains to policy ACCEPT: filter [ OK ]
iptables: Flushing firewall rules: [ OK ]
iptables: Unloading modules: [ OK ]
redis 的基本操作很多,但是本文只是用到了以下 lpush 和 rpop , redis 是一个消息列队,也可以理解成一个管道, lpush 的作用是向这个管道的左边插入一个元素,同理 rpush 是向管道的右边插入元素,而 rpop 是管道的右边取出一个元素。如果还想要更加深入的理解可以去看官方文档 redis中文官方 。
那么,我们可以将 url 放入到这个管道中,假设有 100 个 url ,可以依次插入管道中,然后在多台机器中从这个管道拿出 url 进行抓取,从而达到分布式的效果。
在 windows 中调试需要去网上下载 redis-2.4.5 windows版本,运行服务 E:\redis-2.4.5\64bit\redis-server.exe ,然后在 python 中写下安装库:
pip3.4 install redis
pip3.4 install install redis-py-cluster
建立一个 redis :
#!/usr/bin/python3.4
# -*- coding: utf-8 -*-
import redis
# http://doc.redisfans.com/
pool = redis.ConnectionPool(host='localhost', port=6379)
r = redis.Redis(connection_pool=pool)
向管道中插入 url :
r.lpush("url", "https://www.baidu.com")
r.lpush("url", "http://www.tybai.com/")
查看管道现在的元素个数:
len = r.llen("url")
print(len)
查看管道中的所有元素:
print(r.lrange("url", 0, -1))
取出元素:
print(r.rpop("url").decode())
print(r.rpop("url").decode())
取出完元素后管道应该没有其他的元素了。如果直接想清空管道可以用:
r.flushdb()
分布式基本需要用到的方法就这些,现在开始构建分布式爬虫。将虚拟机的 redis 启动,写一个小脚本给管道插入 100 个 url ,这 100 个 url 是用两个 url 循环生成的,我写的是 insert.py:
#!/usr/bin/python3.4
# -*- coding: utf-8 -*-
import redis
from rediscluster import StrictRedisCluster
'''
遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料
'''
redis_nodes = [{'host': '192.168.230.218', 'port': 6380},
{'host': '192.168.230.218', 'port': 6381},
{'host': '192.168.230.218', 'port': 6382},
{'host': '192.168.230.223', 'port': 6383},
{'host': '192.168.230.223', 'port': 6384},
{'host': '192.168.230.223', 'port': 6385}
]
r = StrictRedisCluster(startup_nodes=redis_nodes)
r.flushdb()
# 增加url到redis里面
def pushToRedis(name, valueList):
for i in range(50):
for item in valueList:
r.lpush(name, item)
name = "url"
urlList = ["https://www.baidu.com", "http://www.tybai.com/"]
# 添加到消息列队中
pushToRedis(name, urlList)
增加权限后直接运行:
chmod +x insert.py
python3.4 insert.py
什么都没返回,再写一个脚本检查是否插入到了 redis 的消息列队中,脚本名 check.py :
#!/usr/bin/python3.4
# -*- coding: utf-8 -*-
'''
遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料
'''
import redis
from rediscluster import StrictRedisCluster
redis_nodes = [{'host': '192.168.230.218', 'port': 6380},
{'host': '192.168.230.218', 'port': 6381},
{'host': '192.168.230.218', 'port': 6382},
{'host': '192.168.230.223', 'port': 6383},
{'host': '192.168.230.223', 'port': 6384},
{'host': '192.168.230.223', 'port': 6385}
]
r = StrictRedisCluster(startup_nodes=redis_nodes)
name = "url"
length = r.llen(name)
print(length)
print(r.lrange(name, 0, -1))
增加权限后直接运行:
chmod +x check.py
python3.4 check.py
运行结果:
现在就需要写两份抓取的代码,分别在两台虚拟机中运行,抓取这 100 个 url ,设置抓取的函数:
import requests
session = requests.session()
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"}
def getHtml(url):
# 修饰头部
headers.update(dict(Referer=url))
# 抓取网页
resp = session.get(url=url, headers=headers)
return resp.content.decode("utf-8", "ignore")
将抓取到的 html 保存到 /home/ttyb/html 中,但是为了区分两台机器抓了哪些 url ,命名按照虚拟机的 ip 命名:
'''
遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料
'''
import socket
import time
# 保存到本地
def saveToLocal(html):
hostname = socket.gethostname()
ipName = ("1" + socket.gethostbyname(hostname) + "#" + str(time.time())).replace(".", "_")
with open("/home/ttyb/html/" + ipName, "w") as fle:
fle.write(html)
fle.close()
设置一个从 redis 取出 url 的函数:
# 从redis中拿到url
def popFromRedis(name):
return r.rpop(name).decode()
最后一个一个的取出 url ,将抓取到的网页保存下来,每次抓取都暂停 1 秒:
'''
遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料
'''
def main():
name = "url"
length = r.llen(name)
for i in range(length):
url = popFromRedis(name)
print(url)
html = getHtml(url)
saveToLocal(html)
time.sleep(1)
if __name__ == "__main__":
time.sleep(10)
main()
这里我将代码写成 spider1.py 和 spider2.py ,分别在两台机器下运行。增加权限后分别在两台机器上运行,第一台虚拟机:
pip3.4 install requests
chmod +x spider1.py
python3.4 spider1.py
第二台虚拟机:
pip3.4 install requests
chmod +x spider2.py
python3.4 spider2.py
运行效果:
运行到最后会报错停止:
Traceback (most recent call last):
File "spider2.py", line 55, in <module>
main()
File "spider2.py", line 46, in main
url = popFromRedis(name)
File "spider2.py", line 22, in popFromRedis
return r.rpop(name).decode()
AttributeError: 'NoneType' object has no attribute 'decode'
因为管道中已经没有 url 了,被全部取完并下载到了 /home/ttyb/html/ 中,现在去查看每台虚拟机抓取的效果:
得到结果,虚拟机1 抓取的网页有 51 个,虚拟机2 抓取的网页有 49 个,分布式抓取完成!
python爬虫学习:分布式抓取的更多相关文章
- 如何让Python爬虫一天抓取100万张网页
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 王平 源自:猿人学Python PS:如有需要Python学习资料的 ...
- 芝麻HTTP:Python爬虫实战之抓取爱问知识人问题并保存至数据库
本次为大家带来的是抓取爱问知识人的问题并将问题和答案保存到数据库的方法,涉及的内容包括: Urllib的用法及异常处理 Beautiful Soup的简单应用 MySQLdb的基础用法 正则表达式的简 ...
- python爬虫 前程无忧网页抓取
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- Python爬虫之一 PySpider 抓取淘宝MM的个人信息和图片
ySpider 是一个非常方便并且功能强大的爬虫框架,支持多线程爬取.JS动态解析,提供了可操作界面.出错重试.定时爬取等等的功能,使用非常人性化. 本篇通过做一个PySpider 项目,来理解 Py ...
- python爬虫学习(7) —— 爬取你的AC代码
上一篇文章中,我们介绍了python爬虫利器--requests,并且拿HDU做了小测试. 这篇文章,我们来爬取一下自己AC的代码. 1 确定ac代码对应的页面 如下图所示,我们一般情况可以通过该顺序 ...
- 【Python爬虫基础】抓取知乎页面所有图片
抓取地址所有图片 #! /usr/bin/env python from urlparse import urlsplit from os.path import basename import ur ...
- 芝麻HTTP:Python爬虫实战之抓取淘宝MM照片
本篇目标 1.抓取淘宝MM的姓名,头像,年龄 2.抓取每一个MM的资料简介以及写真图片 3.把每一个MM的写真图片按照文件夹保存到本地 4.熟悉文件保存的过程 1.URL的格式 在这里我们用到的URL ...
- 【Python爬虫程序】抓取MM131美女图片,并将这些图片下载到本地指定文件夹。
一.项目名称 抓取MM131美女写真图片,并将这些图片下载到本地指定文件夹. 共有6种类型的美女图片: 性感美女 清纯美眉 美女校花 性感车模 旗袍美女 明星写真 抓取后的效果图如下,每个图集是一个独 ...
- Python爬虫学习(二) ——————爬取前程无忧招聘信息并写入excel
作为一名Pythoner,相信大家对Python的就业前景或多或少会有一些关注.索性我们就写一个爬虫去获取一些我们需要的信息,今天我们要爬取的是前程无忧!说干就干!进入到前程无忧的官网,输入关键字&q ...
- python爬虫CSDN文章抓取
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/nealgavin/article/details/27230679 CSDN原则上不让非人浏览訪问. ...
随机推荐
- mongodb01--安装
配置Mongo服务端 安装MongoDB 1.按照操作系统下载http://www.mongodb.org/downloads. 2.在D盘新建MongoDB文件夹(此文件夹为自定义的数据库安装目录D ...
- linux下jiffies定时器和hrtimer高精度定时器【转】
本文转载自:http://blog.csdn.net/dosculler/article/details/7932315 一.jiffies定时器,HZ=100,精度只能达到10ms. 注:采用jif ...
- CodeForces-451E:Devu and Flowers (母函数+组合数+Lucas定理)
Devu wants to decorate his garden with flowers. He has purchased n boxes, where the i-th box contain ...
- CF 949 D Curfew —— 二分答案
题目:http://codeforces.com/contest/949/problem/D 先二分一个答案,让两边都至少满足这个答案: 由于越靠中间的房间越容易满足(被检查的时间靠后),所以策略就是 ...
- WEB开发框架系列教程 (二)页面功能开发(1)
上一节一起创建TEST项目的完整的解决方案 接下来面临的是一个个具体功能页面开发了 在进行开发之前需要对接下来的页面进行分析 可以这么说任何一个项目中都有很多非常基础类的数据维护功能 我们把这类数据归 ...
- asp.net mvc5 使用百度ueditor 本编辑器完整示例(下)配置上传播放视频
通过 asp.net mvc5 使用百度ueditor 本编辑器完整示例(上)介绍,可以上传图片到服务器了,也可以上传小的视频文件,并且由百度编辑器自动加入html5<video>标签播放 ...
- poj 1474 Video Surveillance 【半平面交】
半平面交求多边形的核,注意边是顺时针给出的 //卡精致死于是换(?)了一种求半平面交的方法-- #include<iostream> #include<cstdio> #inc ...
- JAVA值传递和引用传递 以及 实参是否改变
八大数据类型和String 在进行传递的时候 不会改变. 八大数据类型 public class parameterValue { //值传递 public static void main(Str ...
- c语言程序设计案例教程(第2版)笔记(三)—变量、结构体
零散知识点: 变量 :C语言中,每个变量必须先定义后引用.所谓变量存在是指系统为这个变量分配一块存储空间,此时对变量的操作,就是对变量所对应的存储空间中存放的数据进行操作.人们将变量占据 ...
- ElasticSearch | windows 上安装ES
Elastatic需要java JAVA8 环境,确保安装好环境 在windows上安装ES还是比较简单的, 1.首先在官网上下载zip,地址 https://www.elastic.co/downl ...