zoukankan      html  css  js  c++  java
  • 爬虫1.5-ajax数据爬取

    爬虫-ajax数据爬取

    1. ajax数据

    ajax (异步JavaScript 和 XML)(读作阿贾克斯),ajax可以时网页实现异步更新,一般使用的json数据交互,即在不重新加载整个页面也可以对网页的部分进行更新,ajax技术加载的数据在网页源代码中是看不到的,只能看到url加载的html部分

    获取ajax数据的两种方式

    1 分析ajax调用的接口,发现url的参数,再通过代码请求这个接口,直接拿到json数据,有时json数据可能是加密的,或者发送post请求获取json数据并且表单中的数据是按照一定规则写的,这时需要分析js代码,就很麻烦了。

    2 Selenium+chromedriver 获取动态数据,Selenium 相当于可以模拟输入、删除和点击操作以及cookie chromedriver是一个驱动chrome浏览器的驱动程序,使用它可以驱动浏览器。这种方式可以直接获取网页中全部的代码,包括ajax技术加载的数据。例如有的网站点击“更多”按钮后可以加载的数据,将全部被获取。虽然这种方式简单粗暴,但每次请求页面时都会打开一个页面,加载数据和渲染页面,显得过于笨重。

    2. selenium+chromedriver知识准备

    chromedriver是谷歌浏览器的驱动程序,使用selenium可以操作它

    chromedriver.exe需要放在一个非中文目录下

    2.1 selenium+chromedriver简单操作

    form selenium import webdriver
    driver_path = r'D:chromedriverchromedriver.exe'  # 指明路径
    driver = webdriver.Chrome(executable_path=driver_path)  # 创建driver实例,将路径传入
    driver.get("https://www.baidu.com")  # get方式打开百度,注意一定要加https:// 否则会报错
    driver.page_source # 获取源代码,然后可以扔给正则表达式或者xpath解析,这里可以直接获取ajax数据
    driver.close() #关闭一个页面
    driver.quit() #关闭整个浏览器
    

    2.2 常用表单元素

    input type='text/password/email/number' 文本框
    button input [type='submit'] 按钮 例如登陆
    checkbox input type='checkbox' 例如记住密码选项
    select 下拉菜单

    2.3 模拟点击

    driver.get('https://www.douban.com/')
    remenberBtn = driver.find_element_by_id('form_remember')
    remenberBtn.click()
    

    2.4 行为链

    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains  #导入driver和行为链类
    driver_path = r'D:chromedriverchromedriver.exe'   #指定路径
    driver = webdriver.Chrome(executable_path=driver_path)  #创建对象
    driver.get('https://www.qq.com/')   #打开网页
    moveTag = driver.find_element_by_xpath("//div[@class='more-txt']") #定位腾讯网中“更多”按钮
    clickTag = driver.find_element_by_xpath("//ul[@class='sub-list cf']/li[1]")  
    #定位“独家”按钮
    actions =ActionChains(driver)   # 创建行为链对象
    actions.move_to_element(moveTag)   # 移动到定位点
    actions.click(moveTag)  # 点击   好像不点击也可以
    actions.move_to_element(clickTag)  # 移动到”独家“按钮
    actions.click(clickTag) # 点击
    actions.perform()  # 必须调用的函数   否则不会执行之前定义好的行为
    
    # drver.find_element_by_xpath("") 意味着可以使用xpath语法找到想要点击的按钮或输入框
    # 类似的还有id  class  css
    

    2.5 页面等待

    1 隐式等待
    driver.implicitly_wait(x)  # x是等待时间   x秒
    
    2 显示等待
    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    driver_path = r'D:chromedriverchromedriver.exe'
    driver = webdriver.Chrome(executable_path=driver_path)
    driver.get('https://new.qq.com/ch/ori/')
    try:
        WebDriverWait(driver, 10).until(         
            # 这里使用WebDriverWait类填入参数   10代表等待10s未出现则抛出异常
        EC.presence_of_element_located((By.CLASS_NAME, 's ')) 
            #这里就是等待条件 即当class属性=s 被加载后条件达成
    )
    finally:
        print("2222")   # 这样的话当没有等待到期望的条件就可以做其他事情
    

    2.6 窗口

    打开多个窗口
    driver.get('https://new.qq.com/ch/ori/')
    driver.execute_script("window.open('https://www.douban.com/')") 
    #使用JavaScript脚本打开新页面
    
    driver.get('https://new.qq.com/ch/ori/')
    driver.execute_script("window.open('https://www.douban.com/')")   # 打开两个页面
    print(driver.current_url)   # 打印当前url
    driver.switch_to.window(driver.window_handles[1]) #  切换窗口   窗口列表中第二个窗口的索引是1
    print(driver.current_url)  # 打印当前url
    

    2.7 代理ip

    driver_path = r'D:chromedriverchromedriver.exe'
    options = webdriver.ChromeOptions()  # 创建配置对象
    options.add_argument("--proxy-server=http://221.6.32.206:41816")  # 写入配置
    driver = webdriver.Chrome(executable_path=driver_path, options=options)  # 写入参数
    driver.get('https://www.baidu.com/s?wd=ip')
    

    3. selenium+chromedriver实战拉勾网爬虫代码

    # 拉勾网的反爬太恶心了,于是用selenium+chromedriver来爬,结果还是被封了,我去
    
    import re
    import time
    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from lxml import etree
    
    
    class LagouSpider(object):
        def __init__(self):
            driver_path = r'D:chromedriverchromedriver.exe'  # 指定chromedriver 的路径
            self.driver = webdriver.Chrome(executable_path=driver_path)
            self.base_url = 'https://www.lagou.com/jobs/list_python?px=default&city=%E6%88%90%E9%83%BD#filterBox'   # 拉勾网搜索python的页面url
            self.data = []  # 用来存放字典
    
        def get_url_list(self):
            while True:
                self.driver.get(self.base_url)  # 访问拉勾网
                # 获取页面全部文本信息,这里可以直接获取ajax技术返回的数据,
                # 如果用requests库需要找到发送json请求的数据包
                text = self.driver.page_source
                try:
                    # 等待职位信息的url出现,timeout=3s
                    WebDriverWait(self.driver, 3).until(
                        EC.presence_of_element_located((By.CLASS_NAME, 'position_link'))
                    )
                    # 获取url并调用get_info函数
                    url_list = re.findall(r'<a class="position_link" href="(.*?)" target=.*?>', text, re.S)
                    for i in url_list:
                        self.get_info(i)
                finally:
                    # 判断是否已到最后一页
                    if len(re.findall(r'class="pager_next pager_next_disabled"', text, re.S)) != 0:
                        self.driver.quit()
                        break
                    # 找到下一页的位置并点击
                    else:
                        nextPageTag = self.driver.find_element_by_xpath("//div[@class='pager_container']/span[last()]")
                        nextPageTag.click()
    
    
        def get_info(self, url):
            # 打开新窗口,移动driver,不移动无法获取page_source
            self.driver.execute_script("window.open('{}')".format(url))
            self.driver.switch_to.window(self.driver.window_handles[1])
            try:
                # 提取信息,因为职位描述信息的标签实在是太乱了,还是用xpath舒服一点
                html = etree.HTML(self.driver.page_source)
                work_name = re.findall(r'<div class="job-name" title="(.*?)">', self.driver.page_source, re.S)[0]            
                salary = re.findall(r'<span class="salary">(.*?)</span>', self.driver.page_source, re.S)[0]
                # 获取职位描述信息
                temp = html.xpath("//dd[@class='job_bt']//div/p/text()")
                describe = ''
                for i in temp:
                    describe += i
                describe = re.subn(r's*', '', describe)
                temp = {
                    'job_name': work_name,
                    'describe': describe[0],
                    'salary': salary
                }
                print(temp)
                # 放入列表中,方便写入csv或者txt
                self.data.append(temp)
            except:
                # 出错的页面打印出来
                print(url)
                time.sleep(5)
            finally:
                # 关闭页面,移动driver到最开始的base_url
                self.driver.close()
                self.driver.switch_to.window(self.driver.window_handles[0])
                time.sleep(1)
    
        def run(self):
            self.get_url_list()
    
    
    if __name__ == '__main__':
        spider = LagouSpider()
        spider.run()
    
    

    作者:bitterz
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
    如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!
  • 相关阅读:
    leetcode 350. Intersection of Two Arrays II
    leetcode 278. First Bad Version
    leetcode 34. Find First and Last Position of Element in Sorted Array
    leetcode 54. Spiral Matrix
    leetcode 59. Spiral Matrix II
    leetcode 44. Wildcard Matching
    leetcode 10. Regular Expression Matching(正则表达式匹配)
    leetcode 174. Dungeon Game (地下城游戏)
    leetcode 36. Valid Sudoku
    Angular Elements
  • 原文地址:https://www.cnblogs.com/bitterz/p/10195107.html
Copyright © 2011-2022 走看看