首先说一下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()
这样就可以啦~