• 3. selenium



    生产者消费者模型

    import threading
    import requests
    from lxml import etree
    import os
    from urllib import request
    from queue import Queue
    
    # 生产者模型 -- 储存图片连接
    class Producer(threading.Thread):
        headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
        }
    
        def __init__(self, page_queue, img_queue, *args, **kwargs):
            super(Producer, self).__init__(*args, **kwargs)
            self.page_queue = page_queue
            self.img_queue = img_queue
    
        def run(self):
            while True:
                if self.page_queue.empty():
                    break
                url = self.page_queue.get()
                self.parse_page(url)
    
        def parse_page(self, url):
            response = requests.get(url=url,headers=self.headers)
            text = response.text
            html = etree.HTML(text)
    
            img_list = html.xpath('//div[@class="page-content text-center"]/div/a/img')
            for img in img_list:
                img_url = img.xpath('./@data-original')[0]
                img_name = img.xpath('./@alt')[0]+'.jpg'
                self.img_queue.put((img_url, img_name))
    
    # 消费者模型 -- 保存图片
    class Consumer(threading.Thread):
        def __init__(self, page_queue, img_queue, *args, **kwargs):
            super(Consumer, self).__init__(*args, **kwargs)
            self.page_queue = page_queue
            self.img_queue = img_queue
    
        def run(self):
            while True:
                if self.page_queue.empty() and self.img_queue.empty():
                    break
                img_url, img_name = self.img_queue.get()
                request.urlretrieve(img_url, "imgs/" + img_name)
                print(img_name + " 下载完成!")
    
    # 定义一个主方法,该方法向处理方法中传值
    def main():
        page_queue = Queue(50) #存储页码链接队列
        img_queue = Queue(100)#存储解析出来的图片链接队列
        #想要爬取前10也的数据
        for x in range(1, 11):
            url = "https://www.doutula.com/photo/list/?page=%d" % x
            page_queue.put(url) #将10页的页码链接加入到了page_queue
    
        for x in range(3):
            t = Producer(page_queue, img_queue)
            t.start()
    
        for x in range(3):
            t = Consumer(page_queue, img_queue)
            t.start()
    
    
    if __name__ == '__main__':
        main() 
    

    selenium

    1.简介: 基于浏览器自动化的模块。
    2.环境安装:pip install selenium
    3.准备工作:
        - 安装一款浏览器
        - 下载一个浏览器的驱动程序(网上可以直接搜到)
            - http://chromedriver.storage.googleapis.com/index.html -- 谷歌
    4.selenium和爬虫之间的关联
        - 便捷的抓取页面中的数据(可见既可得)
        - 实现模拟登录
    

    1.selenium基本操作

    from selenium import webdriver
    from time import sleep
    
    # 1.实例化一款浏览器对象 -- 参数是浏览器驱动路径
    browser = webdriver.Chrome(executable_path='chromedriver.exe')
    
    # 2.对指定的url发起请求
    browser.get('https://www.jd.com/')
    sleep(2)
    
    # 3.进行标签定位 -- 单节点获取
    search_box = browser.find_element_by_xpath('//*[@id="key"]')
    '''
    多节点获取:
        lis = browser.find_elements_by_xpath('//*[@id="key"]')  # 注意是elements多个s
        print(lis)  # 输出为列表
    '''
    
    '''
    输入文字用send_keys()
    清空文字用clear()
    点击按钮用click()
    '''
    # 4.向定位到的标签中录入文本信息
    search_box.send_keys('华为手机')
    sleep(2)
    
    # 5.触发点击
    browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
    sleep(2)
    
    # js注入 -- 滑轮滚动
    browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    sleep(2)
    
    # 关闭浏览器
    # browser.quit()
    browser.close()
    

    2.selenium 动态加载数据

    # 药监局数据获取 -- http://scxk.nmpa.gov.cn:81/xk/
    
    from selenium import webdriver
    from time import sleep
    from lxml import etree
    
    # 1.实例化浏览器对象
    browser = webdriver.Chrome(executable_path='chromedriver.exe')
    sleep(1) # 睡眠一下加载数据
    # 2.发起请求
    browser.get('http://scxk.nmpa.gov.cn:81/xk/')
    
    # 3.获取页面原码数据
    page_text = browser.page_source
    page_text_list = [page_text]
    for i in range(5):
        # 点击下一页获取页面数据数据
        browser.find_element_by_xpath('//*[@id="pageIto_next"]').click()
        sleep(1) # 睡眠一下加载数据
        page_text_list.append(browser.page_source)
    
    for page_text in page_text_list:
        tree = etree.HTML(page_text) # 实例化对象
        li_list = tree.xpath('//*[@id="gzlist"]/li') # 获取指定标签数据
        for li in li_list:
            title = li.xpath('./dl/@title')[0]
            print(title)
    
    browser.close() # 关闭浏览器
    

    3.动作连

    from selenium import webdriver
    from time import sleep
    from selenium.webdriver import ActionChains # 引入动作连
    
    #实例化一款浏览器对象
    bro = webdriver.Chrome(executable_path='chromedriver.exe')
    bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    sleep(1)
    
    #注意:如果定位的标签是出现在iframe标签之中,则定位失败,需要完成如下操作
    bro.switch_to.frame('iframeResult') # 用iframe的id获取位置
    div_tag = bro.find_element_by_xpath('//*[@id="draggable"]')
    
    #1.实例化一个动作连对象,且将其和指定的浏览器进行关联
    action = ActionChains(bro)
    action.click_and_hold(div_tag) #点击且长按
    for i in range(5):
        action.move_by_offset(15,17).perform() #perform表示让动作连立即执行
        sleep(0.5)
        
    # 释放动作连
    action.release()
    sleep(1)
    
    bro.close()
    

    4.模拟登陆

    安装图片处理工具:
        pip install Pillow
    
    # 12306模拟登陆 : https://kyfw.12306.cn/otn/resources/login.html
    
    from selenium import webdriver
    from time import sleep
    import base64
    import json
    import requests
    #pip install Pillow
    from PIL import Image # 引入图片处理
    from selenium.webdriver import ActionChains #动作连
    
    # 验证码识别函数
    def base64_api(uname, pwd,  img,typeid):
        with open(img,'rb') as f:
            base64_data = base64.b64encode(f.read())
            b64 = base64_data.decode()
        data = {"username": uname, "password": pwd,"typeid":typeid, "image": b64}
        result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
        if result['success']:
            return result["data"]["result"]
        else:
            return result["message"]
        return ""
    
    #实例化一款浏览器对象
    bro = webdriver.Chrome(executable_path='chromedriver.exe')
    bro.get('https://kyfw.12306.cn/otn/resources/login.html')
    sleep(2)
    browser.maximize_window() # 浏览器最大化(全屏)
    bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
    sleep(2)
    bro.find_element_by_xpath('//*[@id="J-userName"]').send_keys('bobo123456')
    sleep(2)
    bro.find_element_by_xpath('//*[@id="J-password"]').send_keys('1234567890')
    sleep(2)
    
    # 验证码操作 -- Windows显示 - 页面与布局需要调到100% 才能截出完整的图片
    # 1.将当前整个页面进行图片保存
    bro.save_screenshot('./main.png')
    # 2.制定裁剪区域
    img_tag = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
    location = img_tag.location # 获取标签的左下角坐标
    size = img_tag.size # 获取标签的尺寸(宽 - 高)
    # rangle就是裁剪区域
    rangle = (int(location['x']),int(location['y']),int(location['x']+size['width']),int(location['y']+size['height']))
    
    # 裁剪出验证码图片 
    i = Image.open('./main.png')
    frame = i.crop(rangle)
    frame.save('./code.png')
    
    # 3.通过打码平台识别验证码
    img_path = "./code.png"
    result = base64_api(uname='bb328410948', pwd='bb328410948', img=img_path,typeid=21)
    print(result) #识别验证码的结果:259,141|28,160
    
    # 259,141|28,160 ==》 [[x,y],[x,y]]
    # 将识别的结果转化为列表形式
    all_list = []
    if '|' in result:
        list_1 = result.split('|')
        count_1 = len(list_1)
        for i in range(count_1):
            xy_list = []
            x = int(list_1[i].split(',')[0])
            y = int(list_1[i].split(',')[1])
            xy_list.append(x)
            xy_list.append(y)
            all_list.append(xy_list)
    else:
        x = int(result.split(',')[0])
        y = int(result.split(',')[1])
        xy_list = []
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
    
    # 4.按照all_list中的位置进行定向点击
    for loc in all_list:
        x = loc[0]
        y = loc[1]
        ActionChains(bro).move_to_element_with_offset(img_tag,x,y).click().perform()
        sleep(0.5)
    
    # 点击登陆
    bro.find_element_by_xpath('//*[@id="J-login"]').click()
    sleep(1)
    bro.quit()
    
    

    爬虫逆向

    思考:如何在Python程序中执行一个js函数,且获取返回值?
     PyExecJS介绍:PyExecJS 是一个可以使用 Python 来模拟运行 JavaScript 的库。
        我们需要pip install PyExecJS对其进行环境安装。
        安装nodejs的开发环境
    
    
    JS混淆:将核心的js函数的实现进行了加密。
    JS反混淆:暴力破解:http://www.bm8.com.cn/jsConfusion/
     - 发条js调试工具
    

    1.气象数据爬取

    # 网站: https://www.aqistudy.cn//html/city_detail.php?v=1.10
    
    ''''
    分析:
        1.该网站是禁用开发者工具
        2.当修改了查询条件后,点击查询按钮,发起了Ajax请求,请求到了我们想要爬取的数据。
            - 如果我们能找到ajax请求的代码,则可以从中提取到:
                - 请求的url
                - 请求的方式
                - 请求参数
                - 对请求到的数据进行的哪些操作
            - 通过火狐浏览器可以找到搜索按钮绑定的点击事件对应的函数:getData()
            - 需要在谷歌浏览器中捕获数据包,全局搜索getData的实现代码,希望从中能找到ajax请求代码。
                - 分析getData函数实现代码:
                    - 在改函数内部没有发现ajax代码,但是发现了另外两个函数的调用。
                    - type=="HOUR"
                - 另两个函数中没有找到ajax代码,发现了另一个函数的调用
                sJwf3VwkSgqmf0Ddr92K(method,param,函数,0.5)
                    method = 'GETDETAIL' or 'GETCITYWEATHER'
                    param = {4个查询条件}
            - 寻找sJwf3VwkSgqmf0Ddr92K函数的定义:
                - 在该函数的定义中找到了ajax请求代码:
                    - url:https://www.aqistudy.cn/apinew/aqistudyapi.php
                    - type:post
                    - 参数:{ h0lgYxgR3: param },param是动态变化,param = pNg63WJXHfm8r(method, object)
    
    思考:如何在Python程序中执行一个js函数,且获取返回值?
     PyExecJS介绍:PyExecJS 是一个可以使用 Python 来模拟运行 JavaScript 的库。
        我们需要pip install PyExecJS对其进行环境安装。
        安装nodejs的开发环境
    
    
    JS混淆:将核心的js函数的实现进行了加密。
    JS反混淆:暴力破解:- 发条js调试工具
     
    '''
    import requests
    import execjs
    
    node = execjs.get() #实例化一个node对象
    ctx = node.compile(open('./test.js',encoding='utf-8').read())# 读取js文件
    
    method = 'GETCITYWEATHER'
    city = '北京'
    type = 'HOUR'
    start_time = '2018-01-25 00:00:00'
    end_time = '2018-01-25 23:00:00'
    jsFuncName = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)
    
    params = ctx.eval(jsFuncName) # 执行js代码
    # print(params)
    
    url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
        'Referer': 'https://www.aqistudy.cn//html/city_detail.php?v=1.10',
        'Cookie':'dcity=%E5%8C%97%E4%BA%AC; UM_distinctid=178f76b93081fd-0840408d87ce26-5771031-1fa400-178f76b930a31b; CNZZDATA5808503=cnzz_eid%3D1742014539-1619057731-%26ntime%3D1619057731'
    }
    params_dic = {
        'h0lgYxgR3':params
    }
    response_text = requests.get(url,headers=headers,params=params_dic).text
    # print(response_text)
    
    #解密
    de = 'dX506x9jVK3vuMMhoz6ZXx("{0}")'.format(response_text)
    text = ctx.eval(de)
    print(text)
    
    

    2.有道翻译在线

    '''
    需要携带的数据
        i: hello
        from: AUTO
        to: AUTO
        smartresult: dict
        client: fanyideskweb
        salt: 16191634764322
        sign: 1fe112b4e634255c0820d6bc99d6f083
        lts: 1619163476432
        bv: 7b7290f9dbb825e1eb29882d0b1fd770
        doctype: json
        version: 2.1
        keyfrom: fanyi.web
        action: FY_BY_REALTlME
    '''
    
    import random
    import requests
    import execjs
    import time
    
    '''
    分析:根据比对发现翻译数据包中只有三个参数是动态变化的.
        - 注意:python的时间戳是10位的,而js是13位。如果将python的时间戳乘以1000保留整数位就得到了标准的js时间戳
        salt:是lts加了一个个位数
        sign:加密数据
        lts:是一个标准的js时间戳
    '''
    
    # 如果请求不成功,把4个响应头键值对都填上,一般都能成功
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36',
        'Cookie':'P_INFO=yinghelaile; OUTFOX_SEARCH_USER_ID=-1061433457@10.108.160.101; OUTFOX_SEARCH_USER_ID_NCOO=4275058.306269712; JSESSIONID=aaan4gy4BLSmv8YLmy8Jx; ___rl__test__cookies=1619163476428',
        'Referer': 'https://fanyi.youdao.com/',
        'Connection': 'keep-alive',
    }
    
    url = 'https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
    lts = int(time.time()*1000) # js时间戳
    salt = int(str(lts)+str(int(random.random()*10))) # 比lst多加一个随机数
    
    word = input('请输入要翻译的单词:')
    
    node = execjs.get()  # 实例化node对象
    # 加载发条工具调试后的js代码
    ctx = node.compile(open('./youdao.js','r',encoding='utf-8').read())
    func = 'sign("{0}","{1}")'.format(word,salt)
    sign = ctx.eval(func) # 执行js函数
    # print(sign)
    
    data = {
        'i': word,
        'from': 'AUTO',
        'to': 'AUTO',
        'smartresult': 'dict',
        'client': 'fanyideskweb',
        'salt': salt,
        'sign': sign,
        'lts': lts,
        'bv': '7b7290f9dbb825e1eb29882d0b1fd770',
        'doctype': 'json',
        'version': 2.1,
        'keyfrom': 'fanyi.web',
        'action': 'FY_BY_REALTlME',
    }
    
    # 发起请求获取响应数据
    json_data = requests.post(url,headers=headers,data=data).json()
    translate = json_data['translateResult'][0][0]['tgt']
    print(translate)
    
    
  • 相关阅读:
    IOS苹果手机背景音乐不能自动播放问题
    手机自动刷视频方法
    elementUI form表单验证不通过的三个原因
    微信扫码登陆js
    地址转码方式
    css 过渡样式 transition
    vue项目打包踩坑记
    overflow
    怎么学习正则表达式?(正则的使用心得)
    微信小程序(template的使用)
  • 原文地址:https://www.cnblogs.com/jia-shu/p/14695520.html
Copyright © 2020-2023  润新知