数据分析
  • 爬虫:通过编写程序员模拟浏览器上网,然后让其去互联网上爬取/获取数据的过程。
  • 分类(使用场景):
  • 通用爬虫:爬取一整张页面数据。“抓取系统”
  • 聚焦爬虫:爬取的就是页面中指定的内容
  • 增量式爬虫:用来检测网站数据更新的情况。只爬取网站最新更新的数据。
  • 协议:客户端和服务器端进行数据交互的某种形式
  • 请求头信息:
  • User-Agent:请求载体的身份标识
  • Connection:close
  • 响应头信息:
  • Content-Type:
  • https:安全
  • 加密方式:
  • 对称秘钥加密:
  • 非对称秘钥加密:
  • 证书秘钥加密:

 

反爬机制: 反反爬:

1.robots.txt协议                    忽略此协议
2.UA测验                            在请求参数中添加headers(模拟网站发请求)
3.验证码                            云打码、超级鹰、打码兔
4.cookie                           用session发送请求
5、检测ip                           找个代理(透明(能发现你的ip)、匿名(可以发现代理服务器的ip,不能发现你的ip)、高匿(既不能发现你的也不能发现代理的ip))
6、动态参数                          动态获取
7、动态加载                          selenium滑动加载

 

 

- requests模块:网络请求的一个模块。
- 环境的安装:pip install requests


- reqeusts模块的作用:
    - 模拟浏览器发请求。
    
- requests模块的编码流程:
    - 1.指定url
    - 2.发起请求
    - 3.获取响应数据
    - 4.持久化存储

 

案例1:爬取sogou首页文本内容

#导入模块
import requests
#指定url
url = 'https://www.sogou.com/'
#发起请求:get方法的返回值就是一个响应对象
response = requests.get(url=url)
#获取响应数据:text属性返回的是字符串形式的响应数据
page_text = response.text
#step_4:持久化存储
with open('./sogou.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

 

案例2:爬取搜狗指定词条搜索后的页面数据

import requests
url = 'https://www.sogou.com/web'
#处理url请求的参数
wd = input('enter a word:')
param = {
    'query':wd
}
response = requests.get(url=url,params=param)
#设置响应数据的编码
response.encoding = 'utf-8'
page_text = response.text
print(page_text)
name = wd+'.html'
with open(name,'w',encoding='utf-8') as fp:
    fp.write(page_text)
    print(name,'爬取成功!')


 

 

 

如何实现聚焦爬虫(数据解析)
  • 编码流程:
  • 指定url
  • 发起请求
  • 获取响应数据
  • 数据解析
  • 持久化存储
  • 如何实现数据解析
  • 正则
  • bs4
  • xpath
  • 数据解析的原理
  • 实现标签定位
  • 将标签中存储的文本内容或者相关的属性值进行提取

 

案例:如何爬取一张图片数据(方法一)

import requests
url = 'https://pic.qiushibaike.com/system/pictures/12176/121763419/medium/GKAGFQXQTVNBYK37.jpg'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
#content二进制形式的图片数据
img_data = response.content  


with open('./qiutu.jpg','wb') as fp:
    fp.write(img_data)

 

案例:如何爬取一张图片数据(方法二)

import requests
from urllib import request
url = 'https://pic.qiushibaike.com/system/pictures/12176/121763419/medium/GKAGFQXQTVNBYK37.jpg'
request.urlretrieve(url=url,filename='./qiubai.jpg')#filename存储文件路径

 

案例:爬取所有的糗图数据

import requests
import os
import re
from urllib import request
url = 'https://www.qiushibaike.com/pic/'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text
#创建一个文件夹用来存储下载好的所有的图片
if not os.path.exists('./qiutu'):   #指定路径
    os.mkdir('./qiutu')
#进行数据解析(img标签)
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
    src = 'https:'+src
    name = src.split('/')[-1]
    img_path = './qiutu/'+name
    request.urlretrieve(src,img_path)
    print(name,'下载成功!')
print('下载完毕,共下载图片数量为:',len(img_src_list))

 

bs4数据解析
  • 环境安装:
  • pip install bs4
  • pip install lxml
  • bs4解析原理
  • 实例化一个BeautifulSoup对象,必须把即将被解析的页面源码加载到该对象中
  • 调用该对象中相关的属性或者方法进行标签的定位和内容的提取
  • 如何实例化一个BeautifulSoup对象
  • 本地加载:
  • soup = BeautifulSoup(fp,'lxml')
  • 网络加载:
  • soup = BeautifulSoup(page_text,'lxml')
相关的属性和方法
  • soup.tagName:定位标签(只可以定位到第一次出现的标签),返回的永远是一个单数
  • soup.find(tagName,attrName="value"):基于属性定位实现的标签定位。返回的永远是一个单数
  • soup.find_all():返回的永远是一个列表
  • 取文本:
  • string:取得标签中直系的文本内容
  • text/get_text():取得的是标签下面所有的文本内容
  • 取属性:tag['attrName']
  • select:使用选择器定位标签。返回的是列表
  • 标签,类,id选择器:select('选择器')
  • 层级选择器:
  • 单层级:'.tang > ul > li
  • 多层级:'.tang li

 

案例:爬取三国演义整片小说内容

import requests
from bs4 import BeautifulSoup
#获取页面源码数据
url = ' http://www.shicimingju.com/book/sanguoyanyi.html'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text


#实例化soup对象
soup = BeautifulSoup(page_text,'lxml')
#解析出章节标题和详情页的链接
li_list = soup.select('.book-mulu > ul > li')
fp = open('./sanguo.txt','w',encoding='utf-8')
for li in li_list:
    title = li.a.string
    detail_url = 'http://www.shicimingju.com'+li.a['href']
    
    #对详情页url发起请求,进行章节内容的解析提取
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    #将详情页中的章节内容解析提取
    detail_soup = BeautifulSoup(detail_page_text,'lxml')
    div_tag = detail_soup.find('div',class_="chapter_content")
    content = div_tag.text
    fp.write(title+':'+content+'\n')
    print(title,'下载存储成功!')
    
fp.close()

 

xpath解析

- 通用性比较强

- 环境的安装:pip install lxml

- 解析原理:

- 1.实例化一个etree对象,且将解析的页面源码加载到该对象中

- 2.使用该对象中的xpath方法结合着xpath表达式进行标签定位和数据解析提取

- etree对象的实例化:

- 本地加载:

tree = etree.parse('filePath')

- 网络加载:

tree = etree.HTML(page_text)

常用的xpath表达式:基于标签的层级实现定位. 返回的永远是一个列表

  • /:从根标签开始实现层级定位
  • //:从任意位置实现标签的定位
  • 属性定位:tag[@attrName="attrValue"]
  • 索引定位://div[@class="tang"]/ul/li[5] 索引值是从1开始
  • 取文本:
  • 取得直系文本内容:/text()
  • 取得所有的文本内容://text()
  • 取属性:/@attrName

 

案例:爬取58二手房的房源信息

from lxml import etree
import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
url = 'https://bj.58.com/shahe/ershoufang/?PGTID=0d30000c-0047-e8f5-0211-cc2e07b06314&ClickID=1'
page_text = requests.get(url=url,headers=headers).text




#数据解析(房屋的名称和价格)
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
all_data_list = []
for li in li_list:
    name = li.xpath('./div[2]/h2/a/text()')[0]#  ./表示的就是li标签
    detail_url = li.xpath('./div[2]/h2/a/@href')[0]
    if 'https:' not in detail_url:
        detail_url = 'https:'+detail_url
        
    price = li.xpath('./div[3]//text()')
    price = ''.join(price)
#     print(name,price,detail_url)
    #获取详情页的页面源码数据,提取解析出房屋概况
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    tree = etree.HTML(detail_page_text)
    desc = tree.xpath('//div[@id="generalSituation"]//text()')
    desc = ''.join(desc)
    dic = {
        'name':name,
        'price':price,
        'desc':desc
    }
    all_data_list.append(dic)
print(all_data_list,len(all_data_list)

 

案例:需求爬取当前页面全部的城市名称https://www.aqistudy.cn/historydata/

url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
#热门城市://div[@class="bottom"]/ul/li/a/text()
#全部城市://div[@class="bottom"]/ul/div[2]/li/a/text()
all_city_names = tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()')
print(all_city_names,len(all_city_names))

 

模拟登陆的意义:

- 爬取基于某些用户的用户信息

 

验证码识别:云打码平台
  • 使用流程:
  • 注册
  • 登陆:
  • 普通用户:
  • 查询剩余提分(充值)
  • 开发者用户:
  • 创建软件:我的软件-》添加新软件(ID,秘钥)
  • 下载示例代码:开发文档-》点此下载:云打码接口DLL-》PythonHTTP示例下载
import http.client, mimetypes, urllib, json, time, requests


######################################################################


class YDMHttp:




    apiurl = 'http://api.yundama.com/api.php'
    username = ''
    password = ''
    appid = ''
    appkey = ''


    def __init__(self, username, password, appid, appkey):
        self.username = username  
        self.password = password
        self.appid = str(appid)
        self.appkey = appkey




    def request(self, fields, files=[]):
        response = self.post_url(self.apiurl, fields, files)
        response = json.loads(response)
        return response
    
    def balance(self):
        data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['balance']
        else:
            return -9001
    
    def login(self):
        data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['uid']
        else:
            return -9001


    def upload(self, filename, codetype, timeout):
        data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
        file = {'file': filename}
        response = self.request(data, file)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['cid']
        else:
            return -9001


    def result(self, cid):
        data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid)}
        response = self.request(data)
        return response and response['text'] or ''




    def decode(self, filename, codetype, timeout):
        cid = self.upload(filename, codetype, timeout)
        if (cid > 0):
            for i in range(0, timeout):
                result = self.result(cid)
                if (result != ''):
                    return cid, result
                else:
                    time.sleep(1)
            return -3003, ''
        else:
            return cid, ''


    def report(self, cid):
        data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid), 'flag': '0'}
        response = self.request(data)
        if (response):
            return response['ret']
        else:
            return -9001


    def post_url(self, url, fields, files=[]):
        for key in files:
            files[key] = open(files[key], 'rb');
        res = requests.post(url, files=files, data=fields)
        return res.text


######################################################################


# 普通用户名
username    = 'bobo328410948'


# 密码
password    = 'bobo328410948'                            


# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid       = 6003                                    


# 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey      = '1f4b564483ae5c907a1d34f8e2f2776c'    


# 图片文件
filename    = 'getimage.jpg'                        


# 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
codetype    = 1004


# 超时时间,秒
timeout     = 30                                    


# 检查
if (username == 'username'):
    print('请设置好相关参数再测试')
else:
    # 初始化
    yundama = YDMHttp(username, password, appid, appkey)


    # 登陆云打码
    uid = yundama.login();
    print('uid: %s' % uid)


    # 查询余额
    balance = yundama.balance();
    print('balance: %s' % balance)


    # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
    cid, result = yundama.decode(filename, codetype, timeout);
    print('cid: %s, result: %s' % (cid, result))


###############################################

 

案例:人人网携带验证码的模拟登陆

import requests
from lxml import etree
from urllib import request
# from CodeClass import YDMHttp


#封装识别验证码图片的函数
def getCodeText(codeType,filePath):
    result = None
        # 普通用户名
    username    = 'bobo328410948'


    # 密码
    password    = 'bobo328410948'                            


    # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
    appid       = 6003                                    


    # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
    appkey      = '1f4b564483ae5c907a1d34f8e2f2776c'    


    # 图片文件
    filename    = filePath                        


    # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
    codetype    = codeType


    # 超时时间,秒
    timeout     = 40                                    


    # 检查
    if (username == 'username'):
        print('请设置好相关参数再测试')
    else:
        # 初始化
        yundama = YDMHttp(username, password, appid, appkey)


        # 登陆云打码
        uid = yundama.login();
        print('uid: %s' % uid)


        # 查询余额
        balance = yundama.balance();
        print('balance: %s' % balance)


        # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
        cid, result = yundama.decode(filename, codetype, timeout);
        print('cid: %s, result: %s' % (cid, result))
    return result
            
url = 'http://www.renren.com/SysHome.do'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers,proxies={'http':'116.228.233.90:8082'}).text
#解析出验证码图片的地址
tree = etree.HTML(page_text)
code_img_url = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
request.urlretrieve(url=code_img_url,filename='./code.jpg')


#使用打码平台识别验证码
code_text = getCodeText(2004,'./code.jpg')
# print(code_text)


#模拟登陆
login_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2019401113761'
data = {
    "email": "www.zhangbowudi@qq.com",
    "icode": code_text,
    "origURL": "http://www.renren.com/home",
    "domain": "renren.com",
    "key_id": "1",
    "captcha_type": "web_login",
    "password": "17108719a8907d7a716631afc519561080a50ea31d92f64ae5f9ccd64b41e4b1",
    "rkey": "465733ef9b05bd790ec81e9347025808",
    "f": "http%3A%2F%2Fwww.renren.com%2F289676607",
}
#创建一个回话对象
session = requests.Session()
#产生cookie
response = session.post(url=login_url,headers=headers,data=data,proxies={'http':'119.180.135.210:8060'})
# print(response.status_code)


# page_text = response.text
# print(page_text)


#该次请求发送必须携带cookie
detail_url = 'http://www.renren.com/289676607/profile'
detail_page_text = session.get(url=detail_url,headers

 

代理:代理服务器

- 快代理

- 西祠代理

- goubanjia

  • 匿名度:
  • 透明:对方服务器知道你使用了代理ip也知道你的真实ip
  • 匿名:知道你使用了代理ip但是不知道你的真实ip
  • 高匿:什么都不知道
  • 类型:
  • http:只可以发起http请求
  • https:只可以发起https的请求

案例:简单代理池应用

http_list = [
    {'http':'60.190.250.120:8080'},
    {'http':'60.190.250.120:8080'},
    {'http':'60.190.250.120:8080'}
]
https_list = [
    {'https':'60.190.250.120:8080'},
    {'https':'60.190.250.120:8080'},
    {'https':'60.190.250.120:8080'}
]
url = 'http://www.baidu.com/s?wd=ip'
page_text = requests.get(url=url,headers=headers,proxies={'http':'60.190.250.120:8080'}).text
with open('./ip.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
import random
url = 'http://www.baidu.com/s?wd=ip'
response = requests.get(url=url,headers=headers,proxies=)
page_text = response.text
if response.url.split(':')[0] == 'http'
with open('./ip.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

 

cookie的应用和处理

- cookie:服务器端记录客户端的相关状态

- 处理cookie的方式:

- 手动处理:不建议

- 自动处理:回话对象Session,该对象可以像requests模块一样进行网络请求的发送(get,post)。session进行的请求发送可以自动携带和处理cookie。

 

 

案例:基于cookie的案例分析:https://xueqiu.com/

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
#自动获取cookie,cookie就会自动存储到session中
session = requests.Session()
session.get('https://xueqiu.com/',headers=headers)




#捕获ajax数据包获取的url
url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
#携带cookie进行的请求发送
dic_json = session.get(url=url,headers=headers).json()
print(dic_json)
#从响应数据中获取详情页的url
# for dic in dic_json['list']:
# #     print(dic)
#     d = dic['data']
#     detail_url = 'https://xueqiu.com'+d['target']
#     print(detail_url

 

  • 验证码处理:打码兔,云打码
  • 模拟登陆:点击登陆按钮对应的post发起请求(参数的处理和携带)
  • 爬取登陆后的先关的页面数据(模拟登陆后会产生cookie)
  • 如何处理cookie:
  • 手动:
  • 自动:回话对象。
  • 代理:
  • 网站
  • 匿名度:
  • 类型:
  • 代理应用在requests中
  • get和post(参数):
  • url
  • headers
  • data/prams
  • proxies
如何提升requests模块爬取数据的效率
  • 多进程或者多线程(不建议)
  • 线程池或者进程池(适当使用)
  • 单线程+异步协程(推荐)

案例:实例化一个线程池提高爬虫效率

import requests
import re
from lxml import etree
from multiprocessing.dummy import Pool
import random
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
def request_video(url):
    return requests.get(url=url,headers=headers).content
def saveVideo(data):
    name = str(random.randint(0,9999))+'.mp4'
    with open(name,'wb') as fp:
        fp.write(data)
        print(name,'下载存储成功!!!')
url = 'https://www.pearvideo.com/category_1'
page_text = requests.get(url=url,headers=headers).text


tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="listvideoListUl"]/li')
#实例化一个线程池对象
pool = Pool(4)
video_url_list = [] #所有的视频连接
for li in li_list:
    detail_url = 'https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    ex = 'srcUrl="(.*?)",vdoUrl='
    video_url = re.findall(ex,detail_page_text,re.S)[0]
    video_url_list.append(video_url)
#异步的获取4个视频的二进制数据
video_data_list = pool.map(request_video,video_url_list)


#进行视频的持久化存储
pool.map(saveVideo,video_data_list

 

selenium
  • 概念:用来完成浏览器自动化相关的操作。可以通过代码的形式制定一些基于浏览器自动化的相关操作(行为动作),当代码执行后,浏览器就会自动触发先关的事件
  • 环境安装:
  • pip install selenium
  • 下载对应浏览器的驱动程序
  • 编码流程:
  • 导包:from selenium import webdriver
  • 实例化某一款浏览器对象
  • 制定相关的行为动作

 

案例:执行js实现滚轮向下滑动

from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='./chromedriver.exe')


bro.get('https://xueqiu.com/')
sleep(5)


#执行js实现滚轮向下滑动
js = 'window.scrollTo(0,document.body.scrollHeight)'   #向下滑动一屏高度,
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)


a_tag = bro.find_element_by_xpath('//*[@id="app"]/div[3]/div/div[1]/div[2]/div[2]/a')
a_tag.click()
sleep(5)
#获取当前浏览器页面数据(动态)
print(bro.page_source)


bro.qui

 

案例:PhantomJs是一款无可视化界面的浏览器(免安装)

from selenium import webdriver
from time import sleep
bro = webdriver.PhantomJS(executable_path=r'C:\Users\Administrator\Desktop\爬虫+数据\爬虫day03\phantomjs-2.1.1-windows\bin\phantomjs.exe')


bro.get('https://xueqiu.com/')
sleep(2)
bro.save_screenshot('./1.png')
#执行js实现滚轮向下滑动
js = 'window.scrollTo(0,document.body.scrollHeight)'
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.save_screenshot('./2.png')
# a_tag = bro.find_element_by_xpath('//*[@id="app"]/div[3]/div/div[1]/div[2]/div[2]/a')
# bro.save_screenshot('./2.png')
# a_tag.click()
sleep(2)
#获取当前浏览器页面数据(动态)
print(bro.page_source)


bro.quit(

 

案例:谷歌无头浏览器

from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options
# 创建一个参数对象,用来控制chrome以无界面模式打开
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')


bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=chrome_options)
bro.get('https://www.baidu.com')
sleep(2)
bro.save_screenshot('1.png')
#标签定位
tag_input = bro.find_element_by_id('kw')
tag_input.send_keys('人民币')
sleep(2)


btn = bro.find_element_by_id('su')
btn.click()
sleep(2)


print(bro.page_source)
bro.quit

 

案例:前进和后退

from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://www.baidu.com')
sleep(1)
bro.get('http://www.goubanjia.com/')
sleep(1)
bro.get('https://www.taobao.com')
sleep(1)


bro.back()
sleep(1)
bro.forward()
sleep(1)
print(bro.page_source)


bro.quit(

 

案例一:动作链

from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains  
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
bro.get(url=url)
#如果定位的标签存在于iframe标签之中,则必须经过switch_to操作在进行标签定位
bro.switch_to.frame('iframeResult')
source_tag = bro.find_element_by_id('draggable')
#创建一个动作连的对象
action = ActionChains(bro)
action.click_and_hold(source_tag)


for i in range(4):
    #perform表示开始执行动作链
    action.move_by_offset(20,0).perform()
    sleep(1)
bro.quit()

案例二:动作链

from selenium import webdriver
from time import sleep
from selenium.webdriver import ChromeOptions
from selenium.webdriver import ActionChains  


option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])


bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
bro.get(url=url)
#如果定位的标签存在于iframe标签之中,则必须经过switch_to操作在进行标签定位
bro.switch_to.frame('iframeResult')
source_tag = bro.find_element_by_id('draggable')
taget_tag = bro.find_element_by_id('droppable')
#创建一个动作连的对象
action = ActionChains(bro)
action.drag_and_drop(source_tag,taget_tag)
action.perform()
sleep(3)
# bro.quit()

 

 

单线程+异步协程(推荐)
  • event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行。程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定。当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行,让另一部分的程序先运行起来。当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态,一旦收到了任务完成的消息,就开始进行下一步。loop就是这个持续不断的监视器。
  • coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
  • task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
  • future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。
  • 另外我们还需要了解 async/await 关键字,它是从 Python 3.5 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。

 

案例:基本使用

import asyncio
#创建一个协程函数
async def hello(name):
    print('hello to :',name)
#获取了一个协程对象
c = hello('bobo')
#创建一个事件循环对象
loop = asyncio.get_event_loop()
#将协程对象注册到事件循环中,然后启动事件循环对象
loop.run_until_complete(c)

 

案例:task的使用

import asyncio
async def hello(name):
    print('hello to :',name)


c = hello('bobo')
loop = asyncio.get_event_loop()
#就协程进行进一步的封装,封装到了task对象中
task = loop.create_task(c)
print(task)
loop.run_until_complete(task)
print(task)

 

案例:future的使用

import asyncio
async def hello(name):
    print('hello to :',name)
c = hello('bobo')
task = asyncio.ensure_future(c)
loop.run_until_complete(task)

 

案例:绑定回调(task)

def callback(task):
    print('i am callback:',task.result())
import asyncio
async def hello(name):
    print('hello to :',name)
    return name
c = hello('bobo')
task = asyncio.ensure_future(c)
#给任务对象绑定一个回调函数
task.add_done_callback(callback)
loop.run_until_complete(task)

 

案例:多任务异步协程(假)

import asyncio
async def request(url):
    print('正在下载:',url)
    sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果
    print('下载成功:',url)
urls = [
    'www.baidu.com',
    'www.taobao.com',
    'www.sogou.com'
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = [] #任务列表,放置多个任务对象
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)   
#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

 

案例:多任务异步协程(真)

import asyncio
async def request(url):
    print('正在下载:',url)
#     sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果
    await asyncio.sleep(2)
    print('下载成功:',url)
urls = [
    'www.baidu.com',
    'www.taobao.com',
    'www.sogou.com'
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = [] #任务列表,放置多个任务对象
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)    
#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

 

实例:多任务异步操作应用到爬虫中(假)

import requests
async def get_page(url):
    print('正在下载:',url)
    #之所以没有实现异步操作,原因是因为requests模块是一个非异步的模块
    response = requests.get(url=url)
    print('响应数据:',response.text)
    print('下载成功:',url)
start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

实例:多任务异步操作应用到爬虫中(真)

支持异步的网络请求的模块:aiohttp
环境安装:pip install aiohttp


import aiohttp
import asyncio
async def get_page(url):
    async with aiohttp.ClientSession() as session:
        async with await session.get(url=url) as response:
            page_text = await response.text() #read()  json()
            print(page_text)
start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

 

实例:如何实现数据解析---任务的绑定回调机制

import aiohttp
import asyncio
#回调函数:解析响应数据
def callback(task):
    print('this is callback()')
    #获取响应数据
    page_text = task.result()
    print('在回调函数中,实现数据解析')
    
async def get_page(url):
    async with aiohttp.ClientSession() as session:
        async with await session.get(url=url) as response:
            page_text = await response.text() #read()  json()
#             print(page_text)
            return page_text
start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    #给任务对象绑定回调函数用于解析响应数据
    task.add_done_callback(callback)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

 

 

回顾

- 概述什么是http协议

- 爬虫中常用头信息

- https中涉及到的三种加密方式

- requests模块的作用及编码流程

- requests如何进行参数封装,为什么要进行参数封装

- 简述目前接触到的反爬机制及其反反爬策略

- 什么是动态加载数据

  • 爬虫的分类
  • 通用爬虫:
  • 聚焦爬虫:
  • 增量式:
  • 爬取图片的两种方式
  • 使用requests
  • urllib模块request中urlretrive
  • 数据解析的基本原理
  • 标签的定位
  • 取文本或取属性
  • xpath解析原理
  • 实例化etree对象,且将源码加载到该对象中
  • 使用xpath方法结合着xpath表达式进行标签定位和数据提取
  • 属性定位[@attrName="value"]
  • 索引定位:[1]
  • / //
  • 取文本: /text() //text()
  • 取属性:/@attrName
  • etree对象实例化的方式
  • 本地加载:parse
  • 网络加载:HTML
  • bs4解析原理
  • .tagName 单数
  • find(属性定位) 单数 find('tagName',attrName="value")
  • find_all 复数
  • Beautiful对象实例化方式
  • 面试题:如何爬取携带标签的指定页面内容
  • 验证码识别
  • 使用流程
  • 开发者用户登陆:
  • 创建一个软件
  • 下载示例代码
  • 模拟登录
  • 实现流程(携带验证码):
  • 对登陆页面进行请求,从请求到的页面源码中解析下载验证码图片
  • 使用打码平台对验证码进行识别
  • 基于登陆按钮发起一个post请求(处理参数)
  • 意义or作用:获取cookie
  • cookie处理
  • 处理方式:
  • 手动处理:不建议(通用性不强)
  • 自动处理:回话对象。requests.Session()
  • 代理操作
  • 为什么使用代理
  • 免费代理ip网站
  • 匿名度
  • 透明:
  • 匿名:
  • 高匿:
  • 类型:
  • http:
  • https:
  • requests如何应用代理
  • proxies = {'http':'ip:port'}
  • 代理池(列表):
  • selenium
  • 作用:可以让浏览器完成相关自动化的操作
  • 和爬虫的关联:
  • 模拟登陆
  • 可以获取动态加载的页面数据
  • 编码流程
  • 导包
  • 实例化浏览器对象(驱动)
  • 制定相关自动化的行为动作
  • 标签定位
  • find系列的函数
  • 节点交互
  • click
  • send_keys
  • 执行js
  • 获取页面源码数据
  • page_source
  • iframe包含标签定位:
  • switch_to.frame(id)
  • 规避selenium被检测
  • 无头浏览器
  • robots.txt
  • UA检测
  • 验证码
  • cookie
  • 检测ip
  • 动态参数(token,key)
  • 动态加载的数据
posted on 2019-05-06 20:24  汩汩-咕咚  阅读(354)  评论(0编辑  收藏  举报