• 网络爬虫(14)-动态页面爬取


    1.Ajax介绍

    Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。 它不是一门编程语言,而是利用JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。发送Ajax请求到网页更新过程,简单分为以下3步:发送请求;解析内容;渲染网页。
    Ajax具有特殊的请求类型,它叫作xhr。

    2.Ajax数据爬取

    # 首先,定义一个方法来获取每次请求的结果。 在请求时,page是一个可变参数,所以我们将它作为方法的参数传递进来,相关代码如下:
    from  urllib.parse import  urlencode 
    import  requests 
    base url = 'https://m.weibo.cn/api/container/getlndex?' 
    headers = { 
    'Host':  'm.weibo.cn', 
    'Referer':'https://m.weibo.cn/u/2830678474',
    'User-Agent':'Mozilla/s.o (Macintosh;  Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML,  like Gecko) 
    Chrome/58.0.3029.110 Safari/537.36','X-Requested-With ':'XMLHttpRequest',
    } 
    def get_page(page)':
    params = { 
    'type':'uid', 
    'value':'2830678474', 
    'containerid':'1076032830678474', 
    'page': page 
    }
    url = base_url + urlencode(params) 
    try: 
        response = requests.get(url, headers=headers) 
        if response.status_code == 200: 
        return response.json() 
    except requests.ConnectionError as e: 
        print(' Error',  e.args)
        
    # 随后,我们需要定义一个解析方法,用来从结果中提取想要的信息,比如这次想保存微博的id、正文、赞数、 评论数和转发数这几个内容,  那么可以先遍历cards,然后获取mblog 中的各个信息,赋值为一个新的字典返回即可:
    from  pyquery import  PyQuery as pq 
    def parse _page (j son): 
        if json: 
        items  = j son. get(' data ') .get('cards ') 
        for item  in  items: 
            item = item.get('mblog') 
            weibo = {} 
            weibo[ 'id'] = item.get('id') 
            weibo['text'] = pq(item.get('text')). text() 
            weibo['attitudes']  = item.get('attitudes_count') 
            weibo [ 'comments '] = item.get('comments_count') 
            weibo['reposts'] = item.get('reposts_count') 
            yield weibo
    
    # 最后,遍历一下page,一共10页,将提取到的结果打印输出即可:
    if name ==  'main': 
        for page in range(l, 11): 
            json = get_page(page) 
            results = parse_page(json) 
        for result in results: 
            print(result)
    
    # 加一个方法将结果保存到MongoDB数据库:
    from  pymongo import MongoClient 
    client = MongoClient () 
    db = client [ 'weibo' ] 
    collection = db['weibo']
    def save_to_mongo(result):
        if collection.insert(result):
            print('save to Mongo')

    2.Selenium库

    Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。

    1)声明浏览器对象

    from  selenium import webdriver 
    browser = webdri ver. Chrome() 
    browser = webdriver. Firefox() 
    browser = webdri ver. Edge() 
    browser = webdriver. PhantomJS() 
    browser= webdriver.Safari() 
    
    # 完成浏览器对象初始化并将其赋值为browser 对象。调用 browser对象,让其执行各个动作以模拟浏览器操作。

    2)访问页面

    from  selenium import webdnver 
    browser = webdriver.Chrome() 
    browser. get (’https://www.taobao.com’ )
    print(browser.page_source) 
    browser. close() 
    
    # 用get()方法来请求网页,参数传入链接URL即可。 

    3)查找节点

    # 单个节点
    find_element_by_id
    find_element_by_name
    find_element_by_xpath
    find_element_by_link_text
    find_element_by_partial_link_text
    find_element_by_tag_name
    find_element_by_class_name
    find_element_by_css_selector
    Selenium提供通用方法find_element(),它需要传入两个参数: 查找方式By和值。find_element(By.ID,id)
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    input_first = browser.find_element(By.ID,'q')
    print(input_first)
    browser.close()
    
    # 多个节点
    要查找所有满足条件的节点,需要用find_elements()这样的方法

    4)节点交互

    Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。 

    from selenium import webdriver
    import time 
    
    browser = webdriver.Chrome()
    browser.get('https://www.taobao.com')
    input = browser.find_element_by_id('q')
    
    # send_keys()方法用于输入文字
    input.send_keys('iPhone')
    time.sleep(1)
    
    # clear()方法用于清空文字
    input.clear()
    input.send_keys('iPad')
    button = browser.find_element_by_class_name('btn-search')
    
    # click()方法用于点击按钮
    button.click()

    5)动作链

    如鼠标拖曳、 键盘按键等,它们没有特定的执行对象,这些动作用另一种方式来执行,那就是动作链。
    
    - 实现一个节点的拖曳操作,将某个节点从一处拖曳到另外一处
    
    # 首先,打开网页中的一个拖曳实例,然后依次选中要拖曳的节点和拖曳到的目标节点,接着声明ActionChains对象并将其赋值为actions变量,然后通过调用actions变量的drag_and_drop()方法,  再调用perform()方法执行动作,此时就完成了拖曳操作
    from  selenium import  webdnver 
    from  selenium.webdriver import  ActionChains 
    browser = webdriver.Chrome() 
    url =’http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    browser.get(url) 
    browser.switch_to.frame('iframeResult')
    source = browser.find_element_by_css selector('#draggable') 
    target= browser.find_element_by_css_selector('#droppable' ) 
    actions = ActionChains(browser) 
    actions.drag_and_drop(source, target) 
    actions.perform() 

    6)JavaScript执行

    对于某些操作,Selenium API并没有提供。 比如,下拉进度条,它可以直接模拟运行JavaScript,
    此时使用execute script()方法即可实现,代码如下:

    from selenium import webdriver 
    browser= webdriver.Chrome() 
    browser. get (’https://www.zhihu.com/explore') 
    browser.execute_script('window.scrollTo(o, document.body.scrollHeight)’) 
    browser.execute_script('alert(”To Bottom”)') 
    
    # 这里就利用execute script()方法将进度条下拉到最底部,然后弹出alert提示框。

    7)获取节点信息

    - 获取属性

    # 使用get_attribute()方法来获取节点的属性
    from  selenium import webdriver 
    from  selenium.webdriver import  ActionChains 
    browser = webdri ver. Chrome() 
    url = 'https://www.zhihu.com/explore' 
    browser. get ( url) 
    logo= browser.find_element_by_id(’zh-top-link-logo’) 
    print(logo) 
    print(logo.get_attribute(’class' )) 

    - 获取文本值

    from  selenium import webdriver 
    browser= webdriver.Chrome() 
    url =’https://www.zhihu.com/explore’ 
    browser. get(url) 
    input = browser.find_element by class name('zu-top-add-question’) 
    print(input.text) 

    - 获取id、位置、标签名和大小

    from. selenium import  webdnver 
    browser = webdriver. Chrome() 
    url =’https://www.zhihu.com/explore'
    browser.get (url) 
    input= browser.find_element_by_class_name(’zu-top-add-question') 
    print(input.id)        # 节点id
    print(input.location)  # 节点页面相对位置
    print(input.tag_name)  # 标签名称
    print(input.size)      # 节点大小

    8)Frame切换

    网页中有一种节点叫作iframe,也就是子Frame,相当于页面的子页面,它的结构和外部网页的结构完全一致。 Selenium打开页面后,它默认是在父级Frame里面操作,而此时如果页面中还有子Frame,它是不能获取到子Frame里面的节点的。 这时就需要使用switch_to.frame()方法来切换Frame。

    import time 
    from  selenium import  webdriver 
    from  selenium.common.exceptions import  NoSuchElementException 
    browser = webdriver.Chrome() 
    url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' 
    browser.get(url) 
    browser.switch_to.frame('iframeresult’) 
    try: 
      logo= browser.find_element_by_class_name('logo') 
    except NoSuchElementException: 
      print(’NO  LOGO') 
    browser.switch_to.parent_frame)
    logo = browser. find_element_by_class_name('logo')
    print(logo) 
    print(logo.text) 

    首先通过switch_to. frame()方法切换到子Frame里面,然后尝试获取父级Frame 里的logo 节点(这是不能找到的),如果找不到的话,就会抛出NoSuchElementException异常,异常被捕捉之后,就会输出NO LOGO。 接下来,重新切换回父级Frame,然后再次重新获取节点,发现此时可以成功获取了。

    - 隐式等待

    使用隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛什1找不到节点的异常。 换句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间是0。

    from  selenium import webdriver 
    browser = webdriver.Chrome() 
    browser.implicitly_wait (10) 
    browser.get(’https://www.zhihu.com/explore' ) 
    input = browser. find_element_by_class_name(’zu-top-add-question’) 
    print(input) 

    - 显式等待

    隐式等中认为固定了等待时间,然而页面的加载时间会受到网络条件的影响。
    显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。 如果在规定时间内加载出这个节点,就返回查找的节点;如果到了规定时间依然没有加载出来,则抛出超时异常。

    # 首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions。 比如,这里传入了presence_of_element_located这个条件,代表节  点出现的意思,其参数是节点的定位元组,也就是ID为q的节点搜索框。
    - 效果:在10秒内如果ID为q的节点(即搜索框)成功加载出来,就返回该节点;如果超过10秒还没有加载出来,就抛出异常。
    
    from  selenium import webdriver 
    from  selenium.webdriver.common.by import  By 
    from  selenium.webdriver.support.ui import WebDriverWait 
    from  selenium.webdriver.support import expected_conditions as EC 
    browser = webdriver.Chrome() 
    browser.get(’https://www.taobao.com/’) 
    wait = WebDriverWait(browser, 10) 
    input = wait. until(EC. presence_of _element_located( (By. ID,’q’))) 
    button = wait.until(EC.element to be clickable((By.CSS_SELECTOR,’.btn search'))) 
    print(input, button) 

    9)前进、后退

    浏览器时都有前进和后退功能,Selenium中分别通过forward()、back()方法实现。

    import time 
    from  selenium import webdnver 
    browser = webdriver.Chrome() 
    browser. get (’https://www.baidu.com/’) 
    browser.get('https://www.taobao.com/’) 
    browser.get(’https://www.python.org/’) 
    browser.back() 
    time.sleep(l) 
    browser. forward() 
    browser. close() 

    10)Cookies

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.zhihu.com/explore')
    print(browser.get_cookies())
    browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
    browser.delete_all_cookies()

    11)选项卡管理

    import  time 
    from  selenium import  webdnver 
    browser = webdriver. Chrome() 
    browser.get(’https://www.baidu.com') 
    browser.execute_script(’window. open()’) 
    print(browser. window _handles) 
    browser.switch_to_window(browser.window_handles[l]) 
    browser.get(’https://www.taobao.com') 
    time.sleep(l) 
    browser.switch_to_window(browser.window_handles(0)) 
    browser.get(’https://python.org')

    12)异常处理

    from  selenium import webdriver 
    from  selenium.common.exceptions import  TimeoutException, NoSuchElementExcephon 
    browser = webdriver.Chrome() 
    try: 
      browser.get('https://www.baidu.com’)
    except TimeoutException: 
      print(' Time Out') 
    try: 
      browser. find_element_by_id(' hello') 
    except NoSuchElementException: 
      print(’No Element’) 
    finally:
      browser.close() 

     

  • 相关阅读:
    【转】双口RAM
    Beep使用
    fcntl函数
    ioctl() 参数
    线程属性:pthread_attr_t
    GPIO
    Linux CGI编程基础
    看门狗watchdog
    Linux库知识大全
    linux进程间通讯
  • 原文地址:https://www.cnblogs.com/Iceredtea/p/12215992.html
Copyright © 2020-2023  润新知