反爬虫相关

1.为何会被反爬虫?php

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

为何网站要反爬虫?web

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

l  数据对于每家公司来讲都是宝贵的资源。在大数据时代,数据的价值愈来愈突出,它是不少公司的战略资源。json

因此,一些有实力的大公司便利用反爬虫技术来阻止别人获取本身网站的数据。浏览器

 

 

2.反爬虫的方式有哪些服务器

在实际的爬取过程当中,反爬虫机制大概能够分为如下3类。cookie

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

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

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. 验证码的处理

待续。。。

相关文章
相关标签/搜索