简易分布式爬虫由两部分组成:中央url仓库和爬虫机器。中央仓库动态维护url队列,对已爬取和未爬取的url做标记,负责做分发任务和对抓取的数据进行校验;爬虫机器向中央仓库请求未爬取的链接,并动态添加新url
[TOC]
统一安装软件
Ubuntu16服务器执行以下操作,分布式时可以通过Xshell在多服务器同时执行。或者将此内容设置为服务器的初始化脚本
sudo apt update
sudo apt install lrzsz 方便Xshell拽托上传文件
wget https://repo.continuum.io/archive/Anaconda2-4.3.1-Linux-x86_64.sh
sudo bash Anaconda2-4.3.1-Linux-x86_64.sh 安装时,需要选择将Anaconda加入环境变量
sudo chmod 777 -R anaconda2/
conda install MySQL-python
conda install pymongo
MongoDB配置
MongoDB安装
"#"注释掉bindIp,允许远程MongoDB远程连接
sudo vi /etc/mongod.conf
net:
#bindIp: 127.0.0.1
port: 27017
security:
authorization: "enabled"
创建管理员
use admin
db.createUser(
{
user: "rec",
pwd: "****",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
创建数据库绑定用户
use admin
db.auth("rec","gogo1357A*")
use db2
db.createUser(
{
user: "rec",
pwd: "****",
roles: [
{ role: "readWrite", db: "db2" },
{ role: "read", db: "db2" }
]
}
)
导出\导入数据
mongoexport --host 127.0.0.1 --port 27017 --db db2 -u rec -p "****" --collection items --out items.json
mongoimport --host 127.0.0.1 --port 27017 --db db2 -u rec -p "****" --collection items --file items.json
mongo rec:gogo1357A*@127.0.0.1:27017/db2 --shell query.js > result.txt
拷贝数据库到本地
db.copyDatabase("fromdb", "todb", "fromhost:27017", username, password) username, password可缺省
运行程序
Xshell多服务器同时终止进程,或开始进程
ps -ef | grep music | grep -v auto | cut -c 9-15 | xargs kill -s 9 同时终止名称中带umusic的进程
nohup python -u music.py > music.log 2>&1 & 带日志统一运行music.py
nohup python -u music.py >/dev/null 2>&1 & 不带日志统一运行music.py
注:名字中包含music、不包含auto的进程;cut截取参数中9-15即pid;xargs引入参数,-s 9强行执行
MySQL相关
修改mysql默认配置
防止单机睡眠时间太长,默认8h,现设置为50s
set global wait_timeout=50;
set global interactive_timeout=50;
MySQL表items
- items_id 专辑号,也即专辑链接。(替换最后一项
https://music.douban.com/subject/27030004/, 即为专辑链接) - status 状态码
- comments_num 为专辑评论数目,时间截至到2017/05/17
- machine_id
为正在爬取当前链接的标记,0表示无,其他为id号。(程序执行时,程序向服务器随机请求)
示例
item_id | comments_num | status | machine_id |
---|---|---|---|
1394541 | 0 | 0 | 532 |
status=-1 | 404,无出度或评论 | ||
status=0 | 等待抓取 | ||
status=1 | 抓取完成 | ||
status=2 | 正在抓取 | ||
status=3 | 评论信息手机完毕 | ||
status=4 | 评论信息正在搜集 |
MySQL表users
- user_id 用户id,也即用户链接。(替换最后一项
https://www.douban.com/people/gongyanc/, 即为用户连接) - user_id_num 用户数字id,-1代表用户已注销或者无头像。(替换最后一项
https://img1.doubanio.com/icon/ul138762062.jpg
ul138762062.jpg为uluser_id_num.jpg,即为头像) - user_title 用户名
- status 状态码,与items表相同
- comments_num 用户评论数目,时间截至到2017/05/17
- machine_id
机器码,0表示无,其他为id号。(程序执行时,程序向服务器随机请求)
示例
user_id | user_id_num | user_title | comments_num | status | machine_id |
---|---|---|---|---|---|
zylovenic | 4190923 | 四季末的唱游 | 11 | 0 | 532 |
MySQL表comments
- item_id 专辑id
- user_id 用户id
- rating 评分。(“立荐”,“推荐”, “还行”, “较差”, “很差”, “空”
分别对应5,4,3,2,1,空) - comment 评论
- comment_time 评论时间
示例
item_id | user_id | rating | comment | comment_time |
---|---|---|---|---|
1394540 | 42864633 | 力荐 | 哈利赫敏跳舞的音乐 | 2010-11-24 |
MySQL初始化代码
CREATE TABLE `items` (
`item_id` INT(11) NOT NULL,
`status` INT(11) NOT NULL,
`comments_num` INT(11) NOT NULL,
`machine_id` INT(11) NOT NULL,
PRIMARY KEY (`item_id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;
CREATE TABLE `users` (
`user_id` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`user_id_num` INT(11) NOT NULL,
`user_title` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`status` INT(11) NOT NULL,
`comments_num` INT(11) NULL DEFAULT NULL,
`machine_id` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`user_id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;
CREATE TABLE `comments` (
`item_id` INT(11) NOT NULL,
`user_id` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`rating` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`comment` TEXT NULL COLLATE 'utf8_unicode_ci',
`comment_time` DATE NULL DEFAULT NULL,
PRIMARY KEY (`item_id`, `user_id`),
INDEX `user_id` (`user_id`),
CONSTRAINT `items_users_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `items` (`item_id`),
CONSTRAINT `items_users_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;
MySQL查询
select count(*) from items where status =3;
update items set status = 1 where status = 3;
UPDATE SET status = 2, machine = 1 WHERE item_id = (SELECT i.item_id FROM (SELECT * FROM items WHERE status = 0) i WHERE i.status = 0 LIMIT 1);
SELECT * FROM items WHERE status = 0 and item_id >= ((SELECT MAX(item_id) FROM items)-(SELECT MIN(item_id) FROM items)) * RAND() + (SELECT MIN(item_id) FROM items) LIMIT 1
INSERT OR IGNORE into items values(26920951,0);
update items set `image`=replace(image, 'spic', 'lpic') WHERE item_id=1394555;
拷贝数据库到本地
mysql>CREATE DATABASE `newdb` DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
#mysqldump db1 -u root -ppassword --add-drop-table | mysql newdb -u root -ppassword
#mysqldump db1 -u root -ppassword --add-drop-table | mysql -h 192.168.1.22 newdb -uroot -ppassword
其他
正则匹配
<a href="https://music.douban.com/subject/27030004/comments/" target="_self">全部 1345 条</a>
u"(?<=target=\"_self\">全部 )\d+(?= 条</a>)", 此处用u或者r, u代表utf8, r代表不用转义字符
处理json文件
#coding:utf-8
import json
tweets = []
for line in open('items.json', 'r'):
tweets.append(json.loads(line))
with open('items.json', 'r') as f:
data = json.load(f)
print data
爬虫代理
#encoding=utf8
import urllib
import socket
socket.setdefaulttimeout(3)
f = open("proxy")
lines = f.readlines()
proxys = []
for i in range(0,len(lines)):
ip = lines[i].strip("\n").split("\t")
proxy_host = "http://"+ip[0]+":"+ip[1]
proxy_temp = {"http":proxy_host}
proxys.append(proxy_temp)
url = "http://ip.chinaz.com/getip.aspx"
for proxy in proxys:
try:
res = urllib.urlopen(url,proxies=proxy).read()
print res
except Exception,e:
print proxy
print e
continue