尝试解决Google站长工具DNS错误提示

我的域名www.fachun.net,一直使用DNSpod的免费服务。

前些日子,google站长工具提示DNS错误,一直没有足够重视,那时候提示错误率5%。

后来发现Google蜘蛛来访、更新索引越来越慢、索引数量也不增长,终于意识到问题严重性。

这个网站在只有几万专辑、页面极简陋时,就曾经实现每天覆盖上百个国家的访客,Google索引超过60万个页面。

但现在Google却一周几乎不更新首页,索引仅仅2万个页面!

dns-error

在站长工具查看记录,发现DNS解析错误率最高的时候,竟然超过20%!

如果是做全球性的网站,最好考虑升级DNSpod收费服务,或者换其他的DNS服务商。

现在我临时更换免费的he.net试试,以观后效。

在  https://dns.he.net/ 注册,并且添加相应的A记录。

在entryDNS注册,并且添加A记录。 https://entrydns.net/

然后去修改域名首选DNS为ns1.he.net

fachun.net.dns

因为这个低端vps没有可用的IPv6地址,我也正在考虑新买一个linode VPS。

禁止YisouSpider访问站点

下午偶然发现有IP来访异常,如下图, 前面6个IP都被封过了:

yisou_spider

经查询,前面几个IP是阿里云的。

在apache的日志中查看对应IP的记录,发现user-agent是YisouSpider,属于阿里一个叫“一搜”的产品。

它是做电影搜索的,但我的网站: http://www.fachun.net只提供音乐内容。

这些爬虫的访问不会给我带来任何好处,还占用系统资源和带宽。可以禁止它抓取页面。

在robots.txt中编辑:

User-agent: YisouSpider   
Disallow: /

然后到urls.py中添加对应的url:

url(r'^robots.txt$', TemplateView.as_view(template_name="robots.txt",
content_type='text/plain; charset=UTF-8')),

重启apache即可。 http://www.fachun.net/robots.txt

实际上,更加自律的爬虫,一般都是晚上服务器空闲的时候,才会来大量抓取内容。

一搜的爬虫似乎应该更加自律一点。

Ubuntu VPS配置轻量级图形桌面LXDE和VNC

前几天我买了个Windows VPS,用于上传文件,1 TB流量很快就用尽了。

为了省钱,今天又买了一个Ubuntu VPS,有2TB的流量,价格比winVPS还便宜。

为了方便地用浏览器上传,而无需额外编码,需要安装图形桌面。

LXDE是首选,它占用资源很少,只需几十MB内存。

1. 配置lxde和vnc server

安装x window:

apt-get install xorg

安装lxde:

apt-get install lxde-core

安装svn server:

apt-get install tightvncserver

第一次运行vnc server生成配置文件,需要输入密码:

tightvncserver :1
tightvncserver -kill :1

编辑~/.vnc/xstartup文件,在尾部添加:

lxterminal &
/usr/bin/lxsession -s LXDE &

启用vnc server:

vncserver -geometry 800x600

2. 下载vnc viewer

在这里下载: http://www.realvnc.com/download/viewer/

打开客户端,输入IP:590x,这里x是x桌面的编号:

vnc-viewer

连接后输入密码,就可以进入桌面了。

3. 解决中文乱码

VPS默认locale是en,程序在创建文件和文件夹的时候会出现乱码。

cd /usr/share/locales
./install-language-pack zh_CN
apt-get install language-pack-zh-hans
apt-get install ttf-wqy-zenhei 
vi /etc/default/locale    
#修改为
#LANG="zh_CN.UTF-8"
#LANGUAGE="zh_CN:zh"

关闭putty,重新打开shell,执行locale,就可以看到语言设置是中文了

4. 接着解决putty中文乱码

在putty的选项中设置: window -> Appearance -> Font Settings
字体选择“新宋体”,脚本选择“中文GB2312”,
window -> Translation -> Remote Character Set选择 UTF-8,
勾选下面的两项:
1. Treate CJK …
2. Caps Lock …
在windows下写的python脚本,所有print输出编码为gbk的字符串,都应该修改为编码为utf8。
 

测试前面写的Django数据防爬程序

写一小段测试代码来测试前面写的数据防爬程序,不停访问某个页面:

实际上REMOTE_HOST是服务器根据自己DNS解析得到的,但我这里测试它能否直接在header中伪装:

import httplib  
import sys
import datetime
import random

headers = {'User-Agent': 'Googlebot/2.1 (+http://www.google.com/bot.html)',
           'Connection': 'keep-alive',
           'REMOTE_HOST': 'www.googlebot.com'}

while True:
    conn = httplib.HTTPConnection("www.fachun.net")
    conn.request(method='GET', url='/album/972-Nine%20Objects%20Of%20Desire/?' + str(random.random()), headers=headers)
    response = conn.getresponse()
    print response.status, datetime.datetime.now()
    if response.status == 403:
        print 'forbidden error, exit'
        sys.exit(-1)
    conn.close()

test-anti-spider-app
数据库中的内容: 继续阅读测试前面写的Django数据防爬程序

Django中实现一个简单的数据防爬取系统

www.fachun.net是我做的一个音乐资源站,因为资源丰富,容易成为他人抓取的目标。

被抓取资源事小,另一方面,爬虫的频繁访问还会严重占用服务器资源。

前期写代码的时候,我已经考虑到防爬问题,做了一些简单的事,比如避免使用数字ID,而是ID + 名字。

例如一个歌手的名字是ABC,ID是36,最终的URL就是:

http://www.fachun.net/musician/36-ABC/

这是爬虫难以直接猜解的。

今天我再写一些额外的代码来限制单个IP请求的频率,实现防爬。有几个要点:

1. 使用MySQL Memory数据库引擎来存储用户IP地址

因为多了个过滤层,响应时间必然增加。应该尽量减小这个影响,把IP放在内存中可以节省查找时间。

原来的应用是InnoDB引擎,所以,需要新建数据库,并在settings.DATABASES中添加它。

2. 目前我的过滤条件是10分钟内请求超过100次(已改为60次),封IP十分钟

3. 搜索引擎百度、Google等的爬虫应该不受过滤,因此,需要特别处理搜索引擎的爬虫。

设IP白名单会再次影响效率,我不希望设用白名单来筛选。

只是检查REMOTE_HOST是否包含googlebot.com、crawl.baidu.com等字符串

1. 修改配置文件,增加数据库

首先新建一个app,我这里命名为robotkiller,执行:

manage.py startapp robotkiller

然后在工程settings.py文件中添加一个数据库,我仍然用同名的robotkiller,并在INSTALLED_APPS中添加robotkiller。

DATABASES = {
    'default': {...},
    'robotkiller': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'robotkiller',                      
        'USER': 'your_user',
        'PASSWORD': 'your_pass',
        'HOST': '127.0.0.1',                    
        'PORT': '3306',
        'OPTIONS': {
            "init_command": "SET storage_engine=MEMORY",
        }
    }
}

models.py中的内容是这样的:

from django.db import models

class RobotKiller(models.Model):
    id = models.IntegerField(primary_key=True)
    ip = models.CharField(max_length=16)    #IP地址
    visits = models.IntegerField()          #请求次数
    time = models.DateTimeField()           #第一次发起请求的时间
    class Meta:
        db_table = 'robotkiller'

记得为ip字段建一个索引(让MySQL为内存数据库再维护个索引,是对是错,暂不深究):

我在settings.py中设置了时区为’Asia/chongqing’,所以,取得时间差,不应该直接用datetime,

而是用django.utils.timezone。下面是我的视图函数:

from models import RobotKiller
from django.utils import timezone

max_visits = 100
min_seconds = 600

def filterIP(request):
    domain = request.META.get('REMOTE_HOST')
    white_list = ['googlebot.com', 'crawl.baidu.com', 'sogou.com', 'bing.com', 'yahoo.com']
    for bot_domain in white_list:
        if domain.find(bot_domain) > 0:
            return bot_domain

    user_ip = request.META['REMOTE_ADDR']

    try:
        record = RobotKiller.objects.using('robotkiller').get(ip=user_ip)
    except RobotKiller.DoesNotExist:
        RobotKiller.objects.using('robotkiller').create(ip=user_ip, visits=1, time=timezone.now())
        return

    passed_seconds = (timezone.now() - record.time).seconds

    if record.visits > max_visits and passed_seconds < min_seconds:
        raise Exception('user ip banned.')
    else:
        if passed_seconds < min_seconds:
            record.visits = record.visits + 1
            record.save()
        else:
            record.visits = 1
            record.time = timezone.now()
            record.save()

上述代码就是基本的过滤逻辑。在urls.py中添加:

from robotkiller import filterIP

然后在需要防爬取的对应app的views.py中添加该函数:

def checkIP(request):
    try:
        filterIP(request)
    except Exception, e:
        if unicode(e) == 'user ip banned.':
            raise PermissionDenied()

接着,在所有视图函数的第一行添加checkIP(request) 就可以过滤所有页面的请求了。

当用户在10分钟内请求了超过100个页面,会得到一个403错误。

可以在模板文件夹下新建一个403.html,自定义出错提示了。

MySQL修改某一列collate时遇到的问题

在测试歌手名排序时,我曾临时地将歌手的name列改成了utf8_bin整理排序,区分大小写。

其他列默认为utf8_general_ci排序。

后来忘记改回来了,

今天测试时发现一个bug,搜歌手输入Linkin Park可以搜到,而linkin park却搜不到:

http://www.fachun.net/search/Linkin%20Park?sid=0

该函数我在django中已经用icontains忽略大小写,

确认view函数没有问题,我排查到原来是name列被错误定义为了utf8_bin排序,所以大小写是不同的。

原先的定义是:

name varchar(100) character set utf8 collate utf8_bin not null;

我直接修改某列,就执行:

alter table musician modify name varchar(100) not null;

这个表也就9000多条记录,执行了半天还一直卡在那里。

show processlist,发现state居然是Locked,无语!

kill对应的id,换成执行:

alter table musician convert to character set utf8 collate utf8_general_ci;

两秒就完成了。

具体原因没有深究,或许MySQL版本较低(我用的5.5),DDL效率总是不尽人意。

在修改记录较多的表时,尤其费时,听说是因为MySQL先copy整个表再做修改。