Django之自定义反爬虫功能
来自CloudWiki
技术要点
1)识别请求来自浏览器还是来自爬虫程序,根据不同的访问方式给出不同的响应。
2)获取客户端IP地址并限制其访问时间间隔,如果来自爬虫程序,则多次访问之间的间隔会很短,判断这种情况并给出相应的响应。
3)使用自定义修饰器实现代码复用。
实现形式
修改views文件
修改questions应用的views.py文件,导入time标准库中的time()函数,并定义修饰器函数isCraw()。
from time import time#用来记录当前时间的函数 ips = [None] #用来存储客户端最后一次访问的IP地址 last = 0 #存储客户端最后一次访问时间
def isCraw(func): def wrapper(*args,**kwargs): global ips,last #声明全局变量 agent = args[0].META.get('HTTP_USER_AGENT') #获得请求的头部信息 if 'Mozilla' not in agent /#不是浏览器 and 'Safari' not in agent / and 'Chrome' not in agent: return HttpResponse('禁止使用爬虫') else: ip = args[0].META.get('REMOTE_ADDR') #客户端ip地址 now = time() if ip==ips[0] and now-last<5: #距离上次访问不超过5秒 return HttpResponse('禁止使用爬虫') last = now ips.pop() ips.append(ip)#更新客户端最后一次访问时间和IP地址 return func(*args,**kwargs) return wrapper
添加修饰器
把定义的修饰器作用到相应的视图函数上,以登录界面为例。
@isCraw def login(request): #退出登录 request.session = {} try: #获取网页参数,用户名和密码 account = request.POST['usr'] password = hashlib.md5(request.POST['pwd'].encode()).hexdigest() #验证用户名和密码 users = Students.objects.filter(account=account,password=password) if users : #登陆成功后添加session信息 request.session['account'] = account #页面跳转 return redirect('/check/') else: return render(request,'login.html',{'msg':'用户名或密码不正确'}) except: return render(request,'login.html',{'msg':None}
运行网站
执行命令,运行网站,使用浏览器打开登录界面,一切正常。
编写爬虫
使用Python模块urllib编写简单爬虫程序,尝试读取登录界面信息,失败。
>>> url = r'http://127.0.0.1:8000/check/login/' >>> import urllib.request >>> with urllib.request.urlopen(url) as fp: print(fp.read().decode())
修改爬虫
修改程序,伪装浏览器访问登录页面,成功。
>>> url = r'http://127.0.0.1:8000/check/login/' >>> import urllib.request >>> headers = {'user-agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64)AppleWobKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36'} >>> req = urllib.request.Request(url=url,headers=headers) >>> with urllib.request.urlopen(req) as fp: print(fp.read().decode())
进一步修改爬虫
进一步修改爬虫程序,连续多次读取登录页面,第一次成功,后面失败。
url = r'http://127.0.0.1:8000/check/login/' import urllib.request headers = {'user-agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64)AppleWobKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36'} for i in range(5): req = urllib.request.Request(url=url,headers=headers) with urllib.request.urlopen(req) as fp: print(fp.read().decode())