简易分布式爬虫由两部分组成:中央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
