一台服务器六小时内获取Tor的轮询及IP数

Published: 2016-05-14

Tags: Python Tor R

本文总阅读量

爬虫代理这两个关键词总能不期而遇。在获取代理的途经中有一个免费的高质量代理方案是使用Tor代理。接下来整理下Python中如何使用Tor代理及对Tor代理进行简单的统计

(一)安装Tor及配置

Fedora:

dnf install tor

编辑 /etc/tor/torrc,去掉下面的注释

ControlPort 9051
HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C

如果想设置新的密码

tor --hash-password mypassword

启动tor

systemctl start tor

查看90509051端口是否开启

[root@the5 py]# netstat -tunlp | grep 9050
tcp        0      0 127.0.0.1:9050          0.0.0.0:*               LISTEN      6919/tor            
[root@the5 py]# netstat -tunlp | grep 9051
tcp        0      0 127.0.0.1:9051          0.0.0.0:*               LISTEN      6919/tor

这样,python就可以通过9051端口对tor进行操作了

(二)Python使用Tor代理

pip install stem

python需要安装stem包来操作tor,它是tor project开发的。去看了官方的文档,相当的齐全,如下是官方的hello world

import getpass
import sys

import stem
import stem.connection

from stem.control import Controller

if __name__ == '__main__':
  try:
    controller = Controller.from_port()
  except stem.SocketError as exc:
    print("Unable to connect to tor on port 9051: %s" % exc)
    sys.exit(1)

  try:
    controller.authenticate()
  except stem.connection.MissingPassword:
    pw = getpass.getpass("Controller password: ")

    try:
      controller.authenticate(password = pw)
    except stem.connection.PasswordAuthFailed:
      print("Unable to authenticate, password is incorrect")
      sys.exit(1)
  except stem.connection.AuthenticationFailure as exc:
    print("Unable to authenticate: %s" % exc)
    sys.exit(1)

  print("Tor is running version %s" % controller.get_version())
  controller.close()

如果需要切换IP,那么可以试试如下代码,应该是在sf找的,原链接找不到了

import time
import socket
import socks
import requests
from stem import Signal
from stem.control import Controller

controller = Controller.from_port(port=9051)

def connectTor():
    socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 , "127.0.0.1", 9050, True)
    socket.socket = socks.socksocket

def renew_tor():
    controller.authenticate()
    controller.signal(Signal.NEWNYM)

def showmyip():
    r = requests.get('http://icanhazip.com/')
    ip_address = r.text.strip())
    print(ip_address)


for i in range(10):
    renew_tor()
    connectTor()
    showmyip()
    time.sleep(10)
  • 上边程序的http://icanhazip.com/会回显你的IP,如果链接不可用了,可以试试http://ifconfig.me/ip,或者自己使用任何web框架,返回ip就行,很好搭建。
  • 测试中发现10s基本上是最小的时间间隔,如果改得再小不会切换IP了,可能官方文档有说明,不过没有详细的去考证

(三)统计数据方案

运行上面的程序能看到终端每隔10s就输出一个IP,还是很开心的。但是有一个疑问就是这些IP的是不是究竟有多少是重复的呢

于是我把代理的IP存入了redis,本地的redis貌似不行...我引入了redis模块会报错,不知道是不是socks的原因,于是曲线救国,用另一个VPS搭建了个flask,来接收ip地址,存入redis的队列中。

下面代码进行取值统计

#!/bin/env python
# -*- coding:utf-8 -*-
import redis

redis = redis.Redis(host="localhost", port=6379, password="dong")

res = redis.lrange("torip", 0, -1)

print res
print "数量:", len(res)
print "数量:", len(set(res))

ip_list = set(res)
ip_dict = {}
for ip in ip_list:
    ip_dict[ip] = res.count(ip)

data = sorted(ip_dict.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)

for item in data:
    print item[1], "\t", item[0]

在收集了100个IP不重复IP的时候运行结果如下:

tor

如图可见,请求了416次才得到了100个IP

这时,我比较好奇,如果再多运行些时间,获得的IP和总的请求量会有什么关系呢

换句话说,Tor的IP会是无穷多的供爬虫使用吗?

带着疑问,我写了点辅助的脚本,比如定时任务,每隔一分钟请求一下统计接口,获取形如83,336的数据,前边的是ip的数量,后边的是请求的次数,然后追加写入到csv文件中。

它看起来是这样的:

1,1
5,6
11,12
13,17
16,22
19,27
24,33
28,38
29,44
30,49
32,54
36,60
40,65
41,71
42,76
45,81
47,87
49,92
52,98
53,103

因为是一分钟记录一次,没10s一个请求,所以我也希望它有一个时间的列,用脚本转化一下

awk '$0=""NR","$0' old.csv > data.csv
1,1,1
2,5,6
3,11,12
4,13,17
5,16,22
6,19,27
7,24,33
8,28,38
9,29,44
10,30,49
11,32,54
12,36,60
13,40,65
14,41,71
15,42,76
16,45,81
17,47,87
18,49,92
19,52,98
20,53,103

本次我用的测试数据:data.csv

更加完整的数据:data-full.csv

刚刚接触R语言,所以照葫芦画瓢,来做个数据可视化~吼吼

照着《R语言实战》的3.3例子修改代码如下:

data = read.table("data.csv", header=FALSE, sep=",")
dose <- data[,1]
drugA <- data[,2]
drugB <- data[,3]
pdf("finish3.pdf")
opar <- par(no.readonly = TRUE)
par(lwd = 2, cex = 1.5, font.lab = 2)
plot(dose, drugA, type = "l", lty = 1, col = "red",
    ylim = c(0, 500), main = "Requests Counts & Ip Number", xlab = "Ip Number",
    ylab = "Requests Counts")
lines(dose, drugB, type = "l", lty = 1,
    col = "blue")
abline(h = c(30), lwd = 1.5, lty = 2, col = "grey")
library(Hmisc)
minor.tick(nx = 3, ny = 3, tick.ratio = 0.5)
legend("topright", inset = 0.05, title = "Desc",
    c("IP", "REQ"), lty = c(1, 1), col = c("red", "blue"))
par(opar)

下面是调整参数后输出的几个pdf截图:

tor

再来个放大的~

tor

一图胜千言,还是有图看着开心~

总结如下:

Tor的IP并不是取之不尽的,至少一台机器六个小时内获得的IP数量一百二三十,而且无论看图片趋势还是上边更完整的数据,IP的数量的增长已然趋近为0,这可能是tor机制的限制

幸运的是,虽然IP数量有限制,但是至少IP是随机轮询的,如果爬虫在不那么高频的访问的情况下,似乎也不会被封。

待验证问题:不知道如果两个VPS一起运行,对ip列表的影响会有多大,每个机器tor网络都会为它分配一个一百多IP的池子吗?那么两个池子的IP重复率又有多少呢?