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
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
    如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!
  • 相关阅读:
    hashilb的使用
    包的导入/软件开发规范/异常处理
    序列化模块/模块/包
    常见模块
    可变数据类型和不可变数据类型
    python-----运算符及while循环
    Python之字符串切片
    第一、二次实训作业
    第二次JAVA作业
    Java学习心得
  • 原文地址:https://www.cnblogs.com/bitterz/p/10195107.html
Copyright © 2011-2022 走看看