反爬虫相关

1.为什么会被反爬虫?

对于一个经常使用爬虫程序获取网页数据的人来说,遭遇到网站的“反爬虫”已经是司空见惯。

为什么网站要反爬虫?

l  爬虫并不是一个真正用户的流量,爬虫会浪费网站的流量,也就是会浪费钱。

l  数据对于每家公司来说都是宝贵的资源。在大数据时代,数据的价值越来越突出,它是很多公司的战略资源。

所以,一些有实力的大公司便利用反爬虫技术来阻止别人获取自己网站的数据。

 

 

2.反爬虫的方式有哪些

在实际的爬取过程中,反爬虫机制大概可以分为以下3类。

l  不返回求取的网页,例如不返回网页或者延迟返回。

l  返回非目标网页,如返回错误页、空白页以及同一页。

l  增加获取数据的难度,例如登录的cookie验证和验证码。

 

 

3.如何反反爬虫

网站利用“反爬虫”来阻止别人获取自己网站的数据,但自古以来都是道高一尺、魔高一丈。写爬虫程序的人们又会利用各种反爬措施来获取网站数据。

而如何让爬虫程序顺利的运行下去,核心的思想就是让爬虫程序看起来像正常的用户操作行为。正常的用户使用计算机访问网站时,使用的是浏览器,并且速度慢,网页切换的时间也不确定,不会短时间浏览很多的网页。所以我们可以在这下方面想办法。

3.1 修改请求头

我们可以使用User-Agent的方法来修改请求头,从而达到顺利获取网页的目的。

from bs4 import BeautifulSoup
from urllib import request,parse,error
import json,re,time,random
import requests

# 请求头
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
}
url = 'https://www.baidu.com/'  # 网址
# 使用requests方法
#r = requests.get(url,headers = headers)
#print(r.text)


# 使用urllib方法
res = request.Request(url,headers=headers)
req = request.urlopen(res).read()  # 获取的的网页是bytes格式的数据
print(req.decode('utf-8'))   # 解码成str格式的数据

除了User-Agent,我们还需要知道其他的http协议的字段,如Host和Referer等。

 

3.2 修改爬虫的时间间隔

爬虫如果爬取的太过频繁,一方面是对网站的压力大、不友好,另外一方面是容易招致网站的反爬虫措施。所以,写爬虫程序的时候最好在访问的间隙设置等待时间。另外设置的时间间隔每次都一样,也容易被看出来。我们可以使用time和random模块来设置非固定的间隔时间。

from bs4 import BeautifulSoup

from urllib import request,parse,error

import json,re,time,random
import requests
# 请求头 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' }
url
= 'https://www.baidu.com/' # 网址 # 使用requests方法 #r = requests.get(url,headers = headers) #print(r.text) # 使用urllib方法 for i in range(10): res = request.Request(url,headers=headers) req = request.urlopen(res).read() # 获取的的网页是bytes格式的数据 print(req.decode('utf-8')) # 解码成str格式的数据 time.sleep(random.randint(0,3) + random.random()) # 设置0-3秒的时间间隔

 

3.3 使用代理

代理(Proxy)是指一种特殊的网络服务,允许一个网络终端(浏览器)通过这个服务与另外一个网络终端(服务器)进行非直接的联系。简单来说就是网络的一个中转之地。代理服务器像一个大的缓冲,这样能明显提高浏览的速度和效率。

而且我们也可以维护一个IP池。从而匿藏我们电脑真正的IP。但是代理的IP池维护起来比较麻烦,而且不稳定。(网上有很多免费的代理IP)

3.3.1使用代理的主要思路

1.从代理ip网站爬取IP地址及端口号并储存

2.验证ip是否能用

3.格式化ip地址

4.在requests中或者urllib中使用代理ip爬取网站

在Requests中使用代理爬取的格式是

import requests
requests.get(url, headers=headers,proxies=proxies)

其中proxies是一个字典其格式为:
对每个ip都有
proxies = {
http: 'http://114.99.7.122:8752'
https: 'https://114.99.7.122:8752'
}

 

3.3.2.代码

# IP地址取自国内髙匿代理IP网站:http://www.xicidaili.com/nn/
# 仅仅爬取首页IP地址就足够一般使用

from bs4 import BeautifulSoup
import urllib
import requests
import random

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
}

def getHTMLText(url, proxies):
    r = requests.get(url, proxies=proxies)
    r.raise_for_status()
    r.encoding = r.apparent_encoding  #获取网页正确的编码格式
    return r.text

#从代理ip网站获取代理ip列表函数,并检测可用性,返回ip列表
def get_ip_list(url):
    web_data = requests.get(url, headers = headers)
    soup = BeautifulSoup(web_data.text, 'lxml')
    ips = soup.find_all('tr')
    ip_list = []
    for i in range(1, len(ips)):
        ip_info = ips[i]
        tds = ip_info.find_all('td')
        ip_list.append(tds[1].text + ':' + tds[2].text)

    # 检测ip可用性,移除不可用ip:
    for ip in ip_list:
        try:
            proxy_host = "https://" + ip
            proxy_temp = {"https": proxy_host}
            res = urllib.request.urlopen(url, proxies=proxy_temp).read()
        except Exception as e:
            ip_list.remove(ip)
            continue
    return ip_list

#从ip池中随机获取ip列表
def get_random_ip(ip_list):
    proxy_list = []
    for ip in ip_list:
        proxy_list.append('http://' + ip)

    print(proxy_list)
    proxy_ip = random.choice(proxy_list)
    proxies = {'http': proxy_ip}
    return proxies

#调用代理
if __name__ == '__main__':
    url = 'http://www.xicidaili.com/nn/'
    url9 = "https://blog.csdn.net/weixin_40372371/article/details/80154707"
    ip_list = get_ip_list(url)
    proxies = get_random_ip(ip_list)
    test = getHTMLText(url9,proxies)
    print(test)

 

4 处理cookie,让网页记住登录信息

使用cookie方法,可以把登录信息给记录下来,再次运行代码的时候可以直接获取之前的登陆状态,从而不用重新登录。

4.1 Opener

当你获取一个URL你使用一个opener。在前面,我们都是使用的默认的opener,也就是urlopen。它是一个特殊的opener,可以理解成opener的一个特殊实例,传入的参数仅仅是url,data,timeout。如果我们需要用到Cookie,只用这个opener是不能达到目的的,所以我们需要创建更一般的opener来实现对Cookie的设置。

4.2 直接获取网站的cookie信息

from urllib import request, parse, error
from http import cookiejar

request_url = 'http://www.baidu.com'

# 此处r是用来防止字符转义的,如果字符串中有'\t'的话,如果不加r就会被转义

user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'

# Keep-Alive功能使客户端到服务器端的连接持续有效

headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'}

# 创建一个cookie对象,不传递参数说明创建了一个空的cookie对象

cookie_obj = cookiejar.CookieJar()

# 创建一个cookie处理器,来管理cookie_obj

handler = request.HTTPCookieProcessor(cookie_obj)

# 初始化一个opener,此opener中所有通信的cookie_obj都会在cookie对象中记录。

# 这个cookie是没有域限制的,也就是全局cookie
opener = request.build_opener(handler)
req = request.Request(request_url, headers=headers)
response = opener.open(req)
#print(response.read().decode('utf-8'))

for obj in cookie_obj:
    print('Name=' + obj.name)
    print('Value=' + obj.value)

 

4.3 将获取到的cookie写入文件

from urllib import request, parse, error
from http import cookiejar

request_url = 'http://www.baidu.com'
filename = 'cookie.txt'

# 此处r是用来防止字符转义的,如果字符串中有'\t'的话,如果不加r就会被转义
user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'

# Keep-Alive功能使客户端到服务器端的连接持续有效
headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'}

# 创建一个MozillaCookie对象,用来保存COOKIE,之后写入文件,注意这里需要传递文件名称作为参数
cookie_obj = cookiejar.MozillaCookieJar(filename)

# 创建一个cookie处理器,来管理cookie_obj
handler = request.HTTPCookieProcessor(cookie_obj)

# 初始化一个opener,此opener中所有通信的cookie_obj都会在cookie对象中记录。这个cookie是没有域限制的,也就是全局cookie
opener = request.build_opener(handler)
req = request.Request(request_url, headers=headers)
response = opener.open(req)

# 保存到cookie文件中
# ignore_discard表示cookies将被丢弃也将它保存下来
# ignore_expires表示如果在该文件中cookies已经存在,则覆盖原文件写入
cookie_obj.save(ignore_discard=True, ignore_expires=True)

 

4.4 从文件中获取Cookie并访问

from urllib import request, parse, error
from http import cookiejar

# 此处r是用来防止字符转义的,如果字符串中有'\t'的话,如果不加r就会被转义
user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'

# Keep-Alive功能使客户端到服务器端的连接持续有效
headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'}

# 请求URL
request_url = 'http://www.baidu.com'

# 记录COOKIE的文件名称
filename = 'cookie.txt'

# 初始化一个MozillaCookie对象
cookie_obj = cookiejar.MozillaCookieJar()

# 从文件中读取cookie到对象中
cookie_obj.load(filename, ignore_discard=True, ignore_expires=True)

# 初始化处理对象,此时的cookie_obj对象是带了文件中保存的COOKIE的
handler = request.HTTPCookieProcessor(cookie_obj)
opener = request.build_opener(handler)
req = request.Request(request_url, headers=headers)
response = opener.open(req)
print(response.read().decode('utf-8'))

 

4.5 模拟登录

import urllib.request, urllib.parse, urllib.error
import http.cookiejar

LOGIN_URL = 'http://www.jobbole.com/wp-admin/admin-ajax.php'
get_url = 'http://www.jobbole.com/'  # 利用cookie请求访问另一个网址
values = {'action': 'user_login', 'user_login': '*****', 'user_pass': '******'}
postdata = urllib.parse.urlencode(values).encode()
user_agent = r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'
headers = {'User-Agent': user_agent}
cookie_filename = 'cookie_jar.txt'
cookie_jar = http.cookiejar.MozillaCookieJar(cookie_filename)
handler = urllib.request.HTTPCookieProcessor(cookie_jar)
opener = urllib.request.build_opener(handler)
request = urllib.request.Request(LOGIN_URL, postdata, headers)
try:
    response = opener.open(request)
    # print(response.read().decode())
except urllib.error.URLError as e:
    print(e.reason)
cookie_jar.save(ignore_discard=True, ignore_expires=True)  # 保存cookie到cookie.txt中
for item in cookie_jar:
    print('Name = ' + item.name)
    print('Value = ' + item.value)
get_request = urllib.request.Request(get_url, headers=headers)
get_response = opener.open(get_request)
print('个人主页' in get_response.read().decode())
 

 

5. 验证码的处理

待续。。。

 

 

 

 
 
 
 
 
 

 

posted @ 2018-11-09 22:20  炫风真是风  阅读(305)  评论(0编辑  收藏  举报