爬虫 + 数据分析 - 3 代理, 模拟登录, 验证码识别, 线程池

  • 代理
  • cookie
  • 模拟登陆
    • 验证码的识别
  • 线程池
  • 单线程+多任务异步协程

 

出现HTTPConnectionPool错误的原因以及解决办法:

  1.连接池资源被耗尽(请求太多又没有关闭连接)

    解决办法: 在headers中加入 'Connection':'close'

  2.ip被封

 

一.代理服务器

  • 代理:代理服务器
  • 基于代理的网站:
    • 站大爷
    • goubanjia
    • 快代理
    • 西祠代理
  • 代理的匿名度:
    • 透明:使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP
    • 匿名:对方服务器可以知道你使用了代理,但不知道你的真实IP。
    • 高匿:对方服务器不知道你使用了代理,更不知道你的真实IP
  • 类型:
    • http:代理服务器只可以转发http协议的请求
    • https:代理服务器只可以转发https协议的请求
  • 编码:
    • 在get或者post方法中应用一个proxies的参数,给其参数赋值为{'http':'ip:port'}

简易版代理应用:

#简单版

import requests
#简易的代理池
proxies_list = [
{'http':'119.190.193.7:8060'},
{'http':'119.190.193.7:8060'},
{'http':'119.190.193.7:8060'},
]

url = 'https://www.baidu.com/s?wd=ip'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'
}
page_text = requests.get(url,headers=headers,proxies={'https':'58.218.200.223:30720'}).text
with open('ip.html','w',encoding='utf-8') as fp:
fp.write(page_text)

升级版代理:

#升级版(减少被封的几率)

import requests
import random

https = [
    {'https':'223.19.212.30:8380'},
    {'https':'221.19.212.30:8380'}
]
http = [
    {'http':'223.19.212.30:8380'},
    {'http':'221.19.212.30:8380'}
]

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
url = 'https://www.baidu.com/s?wd=ip'

if url.split(':')[0] == 'https':
    page_text = requests.get(url=url,headers=headers,proxies=random.choice(https)).text
else:
     page_text = requests.get(url=url,headers=headers,proxies=random.choice(http)).text

with open('./ip.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

cookie处理

  • 处理方式:
    • 手动处理:将cookie的键值对手动添加到headers字典中,然后将headers作用到get或者post方法的headers参数中
    • 自动处理:使用Session。
      • session作用:session可以和requests一样进行请求的发送
      • 特性:使用session发起请求,如果请求过程中产生cookie,则cookie会被自动存储到session中
url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
#创建一个session对象
session = requests.Session()
#获取cookie
session.get('https://xueqiu.com/',headers=headers)
#携带cookie进行的请求发送
session.get(url,headers=headers).json()

 

 

模拟登陆

  • 什么是模拟登陆
    • 使用requests对登陆按钮的请求进行发送
  • 为什么要模拟登陆
    • 有的页面必须登陆之后才显示
 
  • 验证码的识别
    • 线上的打码平台:超级鹰,云打码,打码兔......
    • 超级鹰:http://www.chaojiying.com/
 
  • 超级鹰的使用流程
    • 注册:用户中心身份的账户
    • 登陆:
      • 查看提分的剩余
      • 创建一个软件ID:软件ID-》生成一个软件ID(ID的名称和说明)
      • 下载示例代码:开发文档-》选择语言-》点击下载

 

以下代码是下载的文件中的,内容用的时候需加载:

#!/usr/bin/env python
# coding:utf-8

import requests
from hashlib import md5

class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password =  password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


if __name__ == '__main__':
    chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰用户名的密码', '96001')    #用户中心>>软件ID 生成一个替换 96001
    im = open('a.jpg', 'rb').read()                                                    #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    print chaojiying.PostPic(im, 1902)                                                #1902 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()

 

识别古诗文中的验证码:

#识别古诗文网中的验证码图片

import requests from lxml import etree url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx' page_text = requests.get(url,headers=headers).text tree = etree.HTML(page_text) code_img_src = 'https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0] img_data = requests.get(code_img_src,headers=headers).content with open('./code.jpg','wb') as fp: fp.write(img_data) #使用线上平台识别验证码 chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370') #用户中心>>软件ID 生成一个替换 96001 im = open('code.jpg', 'rb').read() #本地图片文件路径 来替换 a.jpg 有时WIN系统须要// print(chaojiying.PostPic(im, 1902)['pic_str'])

基于古诗文网的模拟登陆:

#识别古诗文网中的验证码图片
s = requests.Session()

url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
page_text = s.get(url,headers=headers).text
tree = etree.HTML(page_text)
code_img_src = 'https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0]
#使用session对验证码图片发请求(会产生cookie)
img_data = s.get(code_img_src,headers=headers).content
with open('./code.jpg','wb') as fp:
    fp.write(img_data)
    
#解析出动态参数的数据值
__VIEWSTATE = tree.xpath('//input[@id="__VIEWSTATE"]/@value')[0]
__VIEWSTATEGENERATOR = tree.xpath('//input[@id="__VIEWSTATEGENERATOR"]/@value')[0]
    
#使用线上平台识别验证码
chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')    #用户中心>>软件ID 生成一个替换 96001
im = open('code.jpg', 'rb').read()                                                    #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
#验证码图片的文本数据
code_img_text = chaojiying.PostPic(im, 1902)['pic_str']
print(code_img_text)


#模拟登陆
login_url = 'https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
data = {
    #动态参数:
    #通常情况下动态参数往往都被隐藏在了前台页面中
    "__VIEWSTATE": __VIEWSTATE,
    "__VIEWSTATEGENERATOR": __VIEWSTATEGENERATOR,
    "from": "http://so.gushiwen.org/user/collect.aspx",
    "email": "[email protected]",
    "pwd": "bobo328410948",
    "code": code_img_text,
    "denglu": "登录",
}

login_page_text = s.post(login_url,headers=headers,data=data).text
with open('gushiwen.html','w',encoding='utf-8') as fp:
    fp.write(login_page_text)

 

线程池的应用

- 异步操作可以和非异步操作结合使用
- 线程池最好只被应用在较为耗时的操作中


import time
def request(url):
    print('正在请求:',url)
    time.sleep(2)
    print('请求成功:',url)
  
start = time.time()

urls = [
    'www.1.com',
    'www.2.com',
    'www.3.com',
    'www.4.com',
]

for url in urls:
    request(url)
    
print(time.time()-start)

打印结果:

正在请求: www.1.com
请求成功: www.1.com
正在请求: www.2.com
请求成功: www.2.com
正在请求: www.3.com
请求成功: www.3.com
正在请求: www.4.com
请求成功: www.4.com
8.001457452774048

 

基于异步:

#基于异步操作
from multiprocessing.dummy import Pool
start = time.time()

pool = Pool(4)
def request(url):
    print('正在请求:',url)
    time.sleep(2)
    print('请求成功:',url)

urls = [
    'www.1.com',
    'www.2.com',
    'www.3.com',
    'www.4.com',
]

pool.map(request,urls)

pool.close()
pool.join()
print(time.time()-start)

打印结果:

正在请求:正在请求: www.2.com
正在请求: www.3.com
正在请求: www.1.com
 www.4.com
请求成功: www.2.com
请求成功: www.3.com
请求成功:请求成功: www.4.com
 www.1.com
2.1071205139160156

 

爬取梨视频的短视频数据

#爬取梨视频的短视频数据
#var contId="1570697",liveStatusUrl="liveStatus.jsp",liveSta="",
# playSta="1",autoPlay=!1,isLiving=!1,isVrVideo=!1,hdflvUrl="",sdflvUrl="",hdUrl="",sdUrl="",ldUrl="",
# srcUrl="https://video.pearvideo.com/mp4/adshort/20190626/cont-1570697-14061078_adpkg-ad_hd.mp4",vdoUrl=srcUrl,skinRes="//www.pearvideo.com/domain/skin",videoCDN="//video.pearvideo.com";
import requests
from lxml import etree
import re
pool = Pool(4)

url = 'https://www.pearvideo.com/category_1'
page_text = requests.get(url,headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="listvideoListUl"]/li')
all_video_urls = []
for li in li_list:
    detail_url = 'https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
    detail_page_text = requests.get(detail_url,headers=headers).text
    #解析出视频的url
    ex = 'srcUrl="(.*?)",vdoUrl'
    video_url = re.findall(ex,detail_page_text,re.S)[0]
    all_video_urls.append(video_url)
    
def dowmload_save(url):
    video_data = requests.get(url,headers=headers).content
    fileName = url.split('/')[-1]
    with open(fileName,'wb') as fp:
        fp.write(video_data)
    print(fileName,'下载成功')
    
#视频数据的请求和持久化存储是比较耗时的,可以基于线程池来实现
pool.map(dowmload_save,all_video_urls)#参数1对应的函数必须只可以有一个参数

爬虫中的异步操作

  • 线程池(适当)
  • 单线程+多任务异步协程(推荐)
    • 协程:coroutine
    • 任务对象:stask
    • 事件循环对象:event_loop
  •     

转载于:https://www.cnblogs.com/lw1095950124/p/11098511.html

你可能感兴趣的:(爬虫 + 数据分析 - 3 代理, 模拟登录, 验证码识别, 线程池)