反爬虫

反爬虫

反爬虫:就是使用任何技术手段阻止批量获取网站信息的方式;其实咱们作的就是了解反爬虫的技术,继而反反爬虫。python

反爬虫的方式

(1)不返回网页;web

  • 网站经过ip访问量反爬虫,对访问进行统计,单个ip访问量超过阈值,则封杀或者输验证码;
  • 经过session(会话控制)访问量反爬虫,session对象存储用户会话所需属性和配置信息,用户在web页跳转,存储在session中变量不会丢失,而是在整个会话中一直存下去,若是一个session的访问量过大,就会进行封杀或者输验证码;
  • 经过User-Agent反爬虫,当用requests库进行爬虫,默认的User-Agen为python-requests/(xxx),服务器判断其不是真正的浏览器会予以封杀;

(2)返回非目标网页,如返回错误页、空白页、同一页;
(3)增长获取难度,如登陆及验证码、12306登录选图片;浏览器

反反爬虫

(1) 修改请求头
若是不修改请求头,网页默认为python-requests/xxx,因此须要修改;也能够作一个User-Agen 的池,但针对User-Agen的访问量进行封锁的很少,通常设置为正常的浏览器的user-Agen就行了。安全

# encoding:utf-8

import requests;
link='http://www.santostang.com/';
r=requests.get(link);
print (r.request.headers);

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'};
r=requests.get(link,headers=headers);
print (r.request.headers);

headers,修改先后对比:服务器

(2)修改爬虫的间隔时间网络

  • 爬虫过于频密,对网站很不友好,或者致使网站的反爬虫。可使用time 库在爬虫访问之间设置必定的间隔时间
t1=time.time();
print ('t1: ',t1);
time.sleep(2);
t2=time.time();
print ('t2: ',t2);
t=t2-t1;
print ('t2-t1: ',t);

加入间隔时间:
session

  • 加入随机的时间,使用一个固定的数字做为时间间隔,不像正经常使用户的行为,可使用random库进行随机数设置;random.randint(0,2)的结果是0/1/2,andom.random()是0~1的随机数,相加得到更随意的sleep时间。
t1=time.time();
print ('t1: ',t1);
sleep_time=random.randint(0,2)+random.random();
time.sleep(sleep_time);
t2=time.time();
print ('t2: ',t2);
print (sleep_time);

运行两次,两次sleep时间不同,如图dom

  • 爬取网页过程当中,加入sleep time,在两次爬虫中添加必定的时间间隔。例如爬取http://www.santostang.com/中多个子网页中的文章题目,考虑到进入子网页也须要爬取该子网页,因此将网页爬取部分封装成函数。
# encoding:utf-8
import requests;
from bs4 import BeautifulSoup;
import time,random;
def scarp_url(link):
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'};
    r=requests.get(link,headers=headers);
    soup=BeautifulSoup(r.text);
    return soup;

link='http://www.santostang.com/';#主网页
soup=scarp_url(link);
post_titles=soup.find_all('h1',class_='post-title');
for each in post_titles:
    title_link=each.a['href'];#进入到具体的博客文章中
    print ("休息一下");
    sleep_time=random.randint(0,2)+random.random();
    time.sleep(sleep_time);
    t1=time.time();
    print ("爬取子网页前时间:",t1);

    print ("开始爬取具体博客子网页");
    soup_title=scarp_url(title_link);
    title=soup_title.find('h1',class_='view-title').text.strip();
    print ("这篇博客名:",title);
    t2=time.time();
    print ("爬取子网页后时间:",t2);

将sleep放在每个网页更改前,红框中以爬取两个但仍是出现错误ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的链接。 是服务器为了维护本身的安全,对于不正常的浏览网页者作的限制。刚开始不知http://www.santostang.com/是不是网页的问题,由于该网址有网页进入不了。因此更换了一个网址(豆瓣),从新测试。函数

import requests;
from bs4 import BeautifulSoup;
import time,random;

def scarp_url(link):
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'};
    r=requests.get(link,headers=headers);
    soup=BeautifulSoup(r.text);
    return soup;

link='https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4';#主网页
soup=scarp_url(link);
post_titles=soup.find_all('li',class_='subject-item');
for each in post_titles:
    info_url=each.find('div',class_='info');
    title_link=info_url.a['href'];#子网页的地址
    print (title_link);·

    print ("休息一下");
    sleep_time=random.randint(0,2)+random.random();
    time.sleep(sleep_time);
    t1=time.time();
    print ("爬取子网页前时间:",t1);

    print ("开始爬取具体豆瓣具体书本的子网页");
    soup_title=scarp_url(title_link);
    title=soup_title.find('span',property='v:itemreviewed').text.strip();
    print ("这书本名:",title);
    t2=time.time();
    print ("爬取子网页后时间:",t2);

爬取结果,是ok的,因此前面一个网页本身的问题哦;但目前还不知道 遇到这种网页应该怎么办。
post

  • 其实时间sleep 能够放在更换网页切换之间,其实很随意。固然也能够不用每次换网页就休息,能够在每次爬取间隔少点,可是屡次爬取后再休息多一点时间,比较符合正常浏览的习惯;
def scarp_url(link):
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'};
    r=requests.get(link,headers=headers);
    soup=BeautifulSoup(r.text);
    return soup;

link='https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4';#主网页
soup=scarp_url(link);
post_titles=soup.find_all('li',class_='subject-item');

scrap_time=0; #计算爬取次数
for each in post_titles:
    info_url=each.find('div',class_='info');
    title_link=info_url.a['href'];
    print (title_link);

    print ("开始爬取具体豆瓣具体书本的子网页");
    soup_title=scarp_url(title_link);
    title=soup_title.find('span',property='v:itemreviewed').text.strip();
    print ("这书本名:",title);
    t2=time.time();
    print ("爬取子网页后时间:",t2);

    scrap_time+=1;
    if scrap_time % 5==0:
        sleep_time=10+random.random();
    else:
        sleep_time=random.randint(0,2)+random.random();
    time.sleep(sleep_time);
    t1=time.time();
    print ("爬取子网页前时间:",t1);

增长一个scrap 次数计数。

(3)使用代理

代理是一种特殊的网络服务,容许一个网络终端(通常为客户端),经过这个服务于另外一个网络终端(通常为服务器)进行非直接的链接,其实就是信息的中转站。好比,直接访问国外的网站速度很慢,就能够用国内的代理服务器中转,数据先从国外某网站到国外的代理服务器,再到计算机,反而会比较快。

所以在爬虫过程当中,能够维护一个代理池,让本身的爬虫程序隐藏本身的真实ip。可是代理ip池较难维护,且不稳定。使用代理ip获取网页的方法,模板以下:

import requests;
link='http://www.santostang.com/';
proxies={'http':'http://xxx.xxxxx.xxxxx',...};#就是多个IP地址的字典
response=requests.get(link,proxies=proxies);

NOTE

  • 代理池,具体没有试过。但应该就是在request.get()中,加个代理池的参数吧。后期用到再查资料吧。
  • 反反爬,能够从headers和sleep中,估计能够搞定蛮多平时的练习网站了吧。
  • 据说后面还有更换ip、处理登录表单和验证码。后面入坑再说吧。
相关文章
相关标签/搜索