python3.8通过python selenium+requests+BeautifulSoup+ BrowserMobProxy对页面进行彻底爬取

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

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

python3.8通过python selenium+requests+BeautifulSoup+ BrowserMobProxy对页面进行彻底爬取

这种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的方法,就能获取想要的字段的属性了

python3.8通过python selenium+requests+BeautifulSoup+ BrowserMobProxy对页面进行彻底爬取

  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()

这样就可以啦~