zoukankan      html  css  js  c++  java
  • python3.8通过python selenium+requests+BeautifulSoup+ BrowserMobProxy对页面进行彻底爬取

    首先说一下requests+BeautifulSoup对页面的解析 安装requests和BeautifulSoup    安装步骤我在这里就不说了

    一、通过requests来读取网页信息  可以通过状态码来判断是否成功。

    这种requests是最基本的,有的网页可能会需要cookie、表单提交登录,还有些网页需要权限的user-agent、通过IP来限制。这些可以在百度上查一下。https://www.cnblogs.com/wyl-0120/p/10358086.html  
    2.通过BeautifulSoup来自定义解析网页
    soup = BeautifulSoup(response_data.text, "html.parser")

    1.1 把用requests读取到的网页文件转化成BeautifulSoup格式

    url_list= soup.find_all("a", href=re.compile('%s' % (www.baidu.com))

    1.2 通过find_all来查找a标签中href属性包括www.baidu.com的标签出来(当然BeautifulSoup还有其他的查找方法,但是本人感觉用的地方不多)

      得到的是一个bs4.element.Tag的列表,然后遍历列表。获取每个Tag的其他属性

    r = re.findall(r"> <b>(.*?)</b>", responseData.text, re.S)

    也可以通过这种根据前后标记来获取数据,这种方法相对更灵活一点。有这两种,基本上页面的数据就可以抓取的差不多了

       但是有些网站的为了防止爬虫。做了一些JavaScript脚本代码。就是说,你加载页面时,获取不到页面的html。只有在触发脚本代码事件。才会渲染出真正的html

      比如:页面的上一页下一页的操作。如果获取不到下一页的html就没办法抓取这个网站的全部页面。这个时候就需要今天的重头戏了python selenium

    二、  python selenium

      selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器

    #1.创建Chrome浏览器对象,这会在电脑上在打开一个浏览器窗口
    browser = webdriver.Chrome()
    browser.get(www.baidu.com')

    在创建浏览器对象时,需要安装浏览器驱动(版本必须和浏览器对应),webdriver.Chrome(path)是有一个参数的,参数就是浏览器驱动路径。(如果把驱动路径放入打path变量中,就可以不写参数了

       WebDriver的常用方法

    1.最大化浏览器
    
    browser.manage().window().maximize();
    
    2.设置固定的浏览器大小
    
    这种方法对采用CSS3和HTML5设计的pc和mobile相互兼容的页面,通过切换窗口大小来实现pc版和mobile版的控制是极好滴。。。。。。
    
    browser.manage().window().setSize(new Dimension(800, 600));
    
    3.浏览器刷新
    
    browser.navigate().refresh();
    
    4.浏览器前进
    
    browser.navigate().forward();
    
    5.浏览器回退
    
    browser.navigate().back();
    
    6.cookie设置
    
    browser.manage().addCookie(new Cookie(name, value));
    
    browser.manage().getCookies();
    
    browser.manage().deleteCookie(new Cookie(name, value));
    

      

     2.1.用BeautifulSoup来处理页面源代码

    html = browser.page_source
    soup = BeautifulSoup(html, "lxml")

     2.2.用WebDriver来处理页面源代码

    元素定位

    find_element_by_id() # 通过元素ID定位
    
    find_element_by_name() # 通过元素Name定位
    
    find_element_by_class_name() # 通过类名定位
    
    find_element_by_tag_name() # 通过元素TagName定位
    
    find_element_by_link_text() # 通过文本内容定位
    
    find_element_by_partial_link_text()
    
    find_element_by_xpath() # 通过Xpath语法定位
    
    find_element_by_css_selector() # 通过选择器定位

    这些都是获取一个element的,如果想获取多个,加s(eg:find_elements_by_name())

    一般用的多的就是find_elements_by_xpath()这个了。

    element_all = browser.find_elements_by_xpath('//div//a[contains(@href, "www.baidu.com")]')

    这个是获取div下的a标签的href属性中包括www.baidu.com的全部WebElement,会得到一个WebElement的列表

    还有一些find_elements_by_xpath()方法

     使用class定位 -- driver.find_element_by_xpath('//input[@class="s_ipt"]')
    
     使用name定位   //form//input[@name="phone"]
    
    【文本定位】使用text()元素的text内容 如://button[text()="登录"]
    
    【模糊定位】使用contains() 包含函数 如://button[contains(text(),"登录")]、//button[contains(@class,"btn")] 除了contains不是=等于
    
    【模糊定位】使用starts-with -- 匹配以xx开头的属性值;ends-with -- 匹配以xx结尾的属性值  如://button[starts-with(@class,"btn")]、//input[ends-with(@class,"-special")]
    
     使用逻辑运算符 -- and、or;如://input[@name="phone" and @datatype="m"]

    上边的都是通过相对路径定位,当然页有绝对路径的 -- 以/ 开头,但是要从根目录开始,比较繁琐,一般不建议使用 如:/html/body/div/a

    通过遍历WebElement的列表可以获取符合条件的WebElement,然后通过WebElement的方法,就能获取想要的字段的属性了

      2.3.访问下一个页面后,想继续操作原来页面的功能会报错 Message: stale element reference: element is not attached to the page document

    访问下个页面分两种形式

      1.打开新页面

        打开新的页面的情况,就要操作浏览器的句柄了,先获取新页面的句柄,然后把新页面关了。再改回原来页面的句柄操作

     window = browser.window_handles
     browser.switch_to.window(window[1])
     browser.close()
     browser.switch_to.window(window[0])  

     如果打开多个浏览器句柄和标签页的对应关系:

    标签页顺序(按照打开顺序):1 2 3 4 5

                 对应的句柄   :0 4 3 2 1

    依次类推

    window[0]代表第一个title页面,window[1]代表最后一个title页面

      2.不打开新页面

        费劲,还没找到更好的解决方案。目前用了一个很笨的方法

    counts_a = len(driver.find_elements_by_class('class name'))
    for i in range(counts_a):
    driver.find_element_by_xpath('//a[@class="class name"][i+1]').click() 

    另外不但进下个页面docement会变,长时间不操作的话,有可能会有意外的页面刷新和弹窗

    WebElement goChooseShiftBt = browser.findElement(By.xpath(goChooseShift));
    //  ..... 中间省略了100行代码
    goChooseShiftBt.click();
    
    // 所以要改成
    WebElement goChooseShiftBt
    = browser.findElement(By.xpath(goChooseShift)); goChooseShiftBt.click(); // ..... 中间省略的100行代码

     三 、BrowserMobProxy获取Ajax请求

      browserMobProxy是java写的一个中间件。允许您操作HTTP请求和响应,捕获HTTP内容,并将性能数据导出为HAR文件。 BMP作为独立的代理服务器运行良好,嵌入Selenium测试时尤其有用。下载地址如下https://github.com/lightbody/browsermob-proxy  Windows你会有一个.bat(linux就选另一个)   之后通过python安装BrowserMobProxy

    from browsermobproxy import Server
    # 这里要写刚下载的.bat路径
       server = Server(r"E:pythonrowsermob-proxy-2.1.4inrowsermob-proxy.bat")

      项目下会有一个server.log日志,如果有问题可以在那里查看

    3.1 browserMobProxy整合selenium

        selenium已经很强大了,可以解决大部分需求,但是有一些bt网站,访问的时候,点F12或查看源代码(Crtl+u)。会发现,源代码就一些样式,啥也没有。那么页面时怎么渲染的呢?

    有前端基础的同学应该知道。如果打开页面就加载全部内容,那么相应的时间会加长。那么就有一种技术出来了——> ajax 叫异步请求(有点类似咱们后台的延迟加载,呃...应该就是一个意思)

    有了异步请求就可以大大的减少服务器的响应时间了。但是对于咱们python爬虫来说,简直就是噩梦。

      但是也不是不能获取的,可以通过浏览骑的network模式,来查看都是请求了那些url。但是咱们做的时自动爬取(爬好多数据总不能一个个的点着去看吧?)。但是问题不大,咱们有 过墙梯 啊!

    browserMobProxy可以查看network中都是请求了那些url。解决异步加载爬取问题

    from time import sleep
    from browsermobproxy import Server
    from selenium.webdriver.chrome.options import Options
    from selenium import webdriver
    
    if __name__ == "__main__":
    # 这里要写刚下载的.bat路径
       server = Server(r"E:pythonrowsermob-proxy-2.1.4inrowsermob-proxy.bat")
       server.start()
       proxy = server.create_proxy()
       chrome_options = Options()
       chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy))
       # https需要加上,要不然回报安全连接问题
       chrome_options.add_argument('--ignore-certificate-errors')
       driver = webdriver.Chrome(options=chrome_options)
       proxy.new_har(options={
          'captureHeaders': True, 'captureContent': True
       })
       driver.get(url)
       # 停上几秒,让页面加载完毕,要不然会有漏的
      sleep(5)
       result = proxy.har
       print(result)
       for entry in result['log']['entries']:
          _url = entry['request']['url']
          #获取异步请求的url
          print(_url)
          #  根据URL找到数据接口,
           if "http://www.baidu.com" in _url:
              _response = entry['response']
              _content = _response['content']
              # 获取接口返回内容
              print(_response)
       server.stop()
       driver.quit()

    这样就可以啦~

     


      
  • 相关阅读:
    Vue基础
    Document
    Document
    Document
    Document
    Document
    Document
    Document
    Document
    Document
  • 原文地址:https://www.cnblogs.com/zbzdqsmh/p/13409584.html
Copyright © 2011-2022 走看看