Tip:我写了一篇直接构造请求获取微博数据的文章,不使用selenium,直接访问url获取到json数据,然后解析即可得到想要的数据的文章,请参考微博博主动态及相册的请求构造规律

=============================以下是正文============================

我们在浏览一些网页的时候,鼠标滚到底,就又会加载出一些新的内容,但是请求的网址是没有变的,这就是Ajax加载的效果。一般去爬取这种网站的时候,往往只能得到一开始加载出来的那些内容,而要利用鼠标滚到底才能继续加载出来的内容是得不到的,所以今天利用selenium来模拟用户登录微博,并模拟鼠标下拉抓取某博主的相册。

准备工作:安装并配置好Python的环境,安装了selenium和浏览器驱动,因为我是用Chrome,所以我就以Chrome来说明了,其他的方法类似。

安装python和配置就不用说了,selenium的安装和简单的使用请见 selenium安装和使用。

思路:模拟用户登录微博(半自动),搜索博主,然后点击她的相册,先获取一次加载出来的相册的照片,然后selenium自动滚动鼠标,再一次获取加载出来的相册的照片,两次的长度(len)如果不一样,说明每次滚动鼠标之后都有新数据加载出来,所以继续循环滚动——获取数据——判断的过程,直到这一次和上一次的数据的长度一样,则说明加载完了,将得到的信息整理之后,利用requests库,下载图片

1. 导入相关的库,打开浏览器

import requests
import time
import re
import random
from selenium import webdriver
from selenium.webdriver.common.keys import Keys  # 输入框回车
from selenium.webdriver.common.by import By  # 与下面的2个都是等待时要用到
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, TimeoutException  # 异常处理driver = webdriver.Chrome()
url = 'https://weibo.com'
driver.get(url)
wait = WebDriverWait(driver, 25)
driver.maximize_window()  # 窗口最大化
login = wait.until(EC.element_to_be_clickable((By.XPATH, '//li/a[@node-type="loginBtn"]')))  # 登录按钮
login.click()

执行上面代码之后,将会自动打开Chrome,然后搜索微博主页,进入登陆页面。

2. 模拟用户输入用户名和密码,这儿有个问题,之前登陆好像不需要验证码,但是可能是登录的次数太频繁,所以有了验证码,先说说输入用户名和密码

执行到这儿,程序将会等待用户输入用户名和密码,回车后就是判断有没有验证码这一步,如果有,就输入验证码,没有就跳过

    try:username = input('请输入账号:')password = input('请输入密码:')user = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item username input_wrap"]/input')))user.send_keys(username)pw = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item password input_wrap"]/input')))pw.send_keys(password)pw.send_keys(Keys.ENTER)except Exception as e:print(e)

判断的是否有验证码的方法是,寻找验证码的输入框,如果找不到,则说明没有,那就可以直接登录了。当然,这儿要用异常处理,否则如果找不到这个输入框节点,程序就会退出了。

code = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item verify"]/input')))  # 验证码输入框

有些验证码我们自己也看不出来,所以这儿增加一个功能,就是看不清的话,可以选择换一张。实现的方法就是,如果输入的字符串的长度小于2,会换下一张,因为验证码都不可能是2个或更少的字符的,所以你随意输入一个字母或数字回车就可以看下一张图,直到输入正确的为止。

            if len(text_code) <= 2:next_code = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, '换一张')))  # 看不清时,可点击换一张next_code.click()time.sleep(2)else:# print(text_code, type(text_code))code.clear()  # 清空验证码输入框code.send_keys(text_code)code.send_keys(Keys.ENTER)  # 输完验证码回车即可登录

这儿增加一个是否登录成功的判断

        if wait.until(EC.element_to_be_clickable((By.XPATH, '//strong[@node-type="follow"]'))):# 这个节点是登录成功之后才会显示的print('登录成功')

3. 登录成功之后,其实我们就可以直接利用浏览器访问目标网址了(相册)。没模拟登录之前,如果直接访问这个链接的话,得到的不是正确的链接,而现在我们已经成功登录,浏览器已经记住了登录的用户的登录信息(cookie),所以让浏览器访问这个链接就可以了

url = 'https://weibo.com/p/1005052331498495/photos?from=page_100505&mod=TAB#place'
driver.get(url)  # 在该窗口直接访问微博相册

然后获取第一次的数据

pictures = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div[@class="photo_cont"]/a/img')))

利用循环,一次次的将鼠标滚到最下面,然后获取所有的图片的链接,根据两次的长度是否相等来判断网页是否已经加载完

driver.execute_script(js)
time.sleep(2)
pictures1 = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div[@class="photo_cont"]/a/img')))
if len(pictures1) == len(pictures):pictures = pictures1break
else:pictures = pictures1continue

4. 完成后,就会得到一个pictures列表,这个列表装的就是所有图片节点的信息,然后利用get_attribute()获取属性src(图片的链接就是这个属性的值)。

但是,得到的这些图片的网址只是小图的网址,而你可以将几张对应的小图和大图的网址放在一起对比,找出规律之后,就可以利用小图的地址构造出大图的地址,然后就是图片的下载了。这里要注意的就是下载图片,文件的打开方式是'wb',写入方式是.content;如果全是用selenium来实现的话还好,但是现在用requests去访问图片的链接,所以基本的防止被封IP的步骤还是要有,这儿增加了一个请求头(模拟浏览器),还有代理IP;代理IP的实现:去代理IP的网站找一些稳定的IP,然后构造成标准的proxies之后,利用random库下的choice方法,实现每次都是随机的挑选一个IP来访问,这样会降低被封的可能。另外,我们爬人家的网站,也不要太狠,频率降低一点,友好一点。

            img = requests.get(pics[i], headers=headers, proxies=proxies)if i % 20 == 0:time.sleep(5)if img.status_code == 200:with open('pic'+str(i+1)+'.jpg', 'wb') as f:f.write(img.content)# print('第{}张图爬取成功'.format(str(i+1)).center(20, '='))else:print('第{}张图爬取失败'.format(str(i+1)))

总结:

(1)   整个过程基本都需要进行异常处理,因为只要有一步出错,程序就终止了;

(2)  使用selenium有一个很重要的点,就是等待的问题, 因为网页加载是需要时间的,受网速的影响。我的网速很慢,所以我设置的等待时间都很相对较长。关于selenium的等待问题还有鼠标的各种操作, 有一篇文章写的很好,转自:selenium_对浏览器操作、鼠标操作等总结

(3)  这一次爬取的和以前的相比,最明显的就是可以爬取需要登录的网页了,当然目前验证码的识别还没说,所以才说这是半自动登录方式;

(4)  可以爬取Ajax加载的网页了;

(5)  学到的知识点:

1>>wait = WebDriverWait(driver, 25),最长等待时间设置为25s。

2>>wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div[@class="photo_cont"]/a/img'))),(By.XPATH)等待条件是xpath 里的所有节点出现

3>>wait.until(EC.element_to_be_clickable((By.LINK_TEXT, '换一张'))) ,clickable,可点击,即等待By.LINK_TEXT节点可以点击。

4>>wait.until(EC.element_to_be_clickable((By.XPATH, '//strong[@node-type="follow"]'))) ,与第三点一样的意思,只是获取节点的语法不同而已。等待条件可点击

5>>'''driver.executu_script('window.open()')   # 打开新窗口
                    print('打开窗口')
                    driver.switch_to_window(driver.window_handles[1])  # 切换到该窗口
                    print('切换到窗口')
                ''' ,不知道为什么,pycharm里不能用这种方法打开一个新的窗口,但是在python自带的编辑器里是可以的。

6>>js = "document.documentElement.scrollTop=500000" # scrollTop的值就是距离网页顶端的像素值,0就表示在顶端,
driver.execute_script(js),滚动鼠标的操作

7>>利用滚动鼠标+循环+判断两次得到的节点的长度来实现Ajax加载网页的爬取,结合第二点

8>>selenium中的xpath的使用和常规在比如requests中的使用是有一定区别的。在requests中使用时,可以直接获取到某个标签的文本或属性的信息,比如html等于下面这一段

如果使用一般的方法,使用xpath要获得“陌生人说的情话,最为致命”这句话的表达式应该是

html.xpath('//div[@class="content"]/a/text()')

这样就可以直接获取到,没问题,那么在selenium中呢

比如我这样写

browser.find_element_by_xpath('//div[@class="content"]/a/text()')那么你得到的可能是下面的这种错误提示

同样,如果你想获取的是这个节点的某个属性值呢,第一种情况下,你可以直接html.xpath('//div[@class="content"]/a/@class')这样就可以得到这个节点的class属性的值,但是在selenium中同样是不行的。这是因为selenium它得到的是一个element,是一个节点,而不能直接得到这个节点的值。那么在selenium中如何获取,某个节点的属性和文本内容呢。

input = browser.find_element_by_xpath('//div[@class="content"]/a')
input.get_attribute('class')  # 得到这个节点的class属性的值
input.get_attribute('textContent')  # 方法一:得到这个节点的文本信息
print(input.text)  # 方法二:得到这个节点的文本信息

这样就可以得到一个字符串,内容就是节点的文本信息。有时这个信息可能会有一些多余的空格或换行,因为这是字符串,所以可以利用字符串的.strip()去掉空格和换行

有些朋友私信我要源码,这是去年写的了,还能不能跑各自去改吧:

import requests
import time
import re
import random
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, TimeoutExceptiondef LoGoin():'''登录操作:return: None'''url = 'https://weibo.com'driver.get(url)wait = WebDriverWait(driver, 25)driver.maximize_window()  # 窗口最大化login = wait.until(EC.element_to_be_clickable((By.XPATH, '//li/a[@node-type="loginBtn"]')))  # 登录按钮login.click()try:username = input('请输入账号:')password = input('请输入密码:')user = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item username input_wrap"]/input')))user.send_keys(username)pw = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item password input_wrap"]/input')))pw.send_keys(password)pw.send_keys(Keys.ENTER)except Exception as e:print(e)while True:try:# 判断验证码是否存在,若存在则输入验证码code = wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="item verify"]/input')))  # 验证码输入框time.sleep(2)code.click()code.send_keys('aaa')  # 先模拟输入,一会儿输入正确的验证码时,要先清空这个输入框text_code = input('请输入验证码:')if len(text_code) <= 2:next_code = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, '换一张')))  # 看不清时,可点击换一张next_code.click()time.sleep(2)else:# print(text_code, type(text_code))code.clear()  # 清空验证码输入框code.send_keys(text_code)code.send_keys(Keys.ENTER)  # 输完验证码回车即可登录breakexcept NoSuchElementException:print('不需要验证码')breaktry:if wait.until(EC.element_to_be_clickable((By.XPATH, '//strong[@node-type="follow"]'))):# 这个节点是登录成功之后才会显示的print('登录成功')except NoSuchElementException or TimeoutException:print('登录失败\n')def craw_pic():'''爬取图片:return: 所有完整图片的链接(经过构造了)'''wait = WebDriverWait(driver, 25)url = 'https://weibo.com/p/1005052331498495/photos?from=page_100505&mod=TAB#place'driver.get(url)  # 在该新的窗口直接访问微博相册print('正在努力访问相册.....')time.sleep(15)pictures = driver.find_elements_by_xpath('//div[@class="photo_cont"]/a/img')js = "document.documentElement.scrollTop=500000"for i in range(50):try:driver.execute_script(js)time.sleep(2)pictures1 = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div[@class="photo_cont"]/a/img')))if len(pictures1) == len(pictures):pictures = pictures1breakelse:pictures = pictures1continueexcept Exception as e:print(e)print('访问成功')if pictures:print('相册总共有{}张图'.format(len(pictures)))pics = []for pic in pictures:try:cen_pic = pic.get_attribute('src')# print('获取属性')new_cen_pic = re.compile('\/\/.*?\/.*?\/(.*?)\?.*?').findall(cen_pic)pics.append('https://wx1.sinaimg.cn/mw1024/'+new_cen_pic[0])# print('构造链接')except Exception as e:print(e)# print('返回')return picsdef save_pic(pics):print('开始下载图片.....')headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML,'' like Gecko) Chrome/68.0.3440.106 Safari/537.36'}proxy = [{'http': 'http://180.110.212.36:8118'}, {'http': 'http://122.246.49.135:8010'},{'http': 'http://111.155.116.245:8123'}, {'http': 'http://123.56.169.22:3128'}]proxies = random.choice(proxy)print(proxies)for i in range(len(pics)):try:img = requests.get(pics[i], headers=headers, proxies=proxies)if i % 20 == 0:time.sleep(5)if img.status_code == 200:with open('D:/Projects/p1/pictures/pic'+str(i+1)+'.jpg', 'wb') as f:f.write(img.content)# print('第{}张图爬取成功'.format(str(i+1)).center(20, '='))else:print('第{}张图爬取失败'.format(str(i+1)))except Exception as e:print('失败原因:'.format(e))if __name__ == '__main__':t1 = time.time()driver = webdriver.Chrome()LoGoin()t2 = time.time()pic_list = craw_pic()t3 = time.time()save_pic(pic_list)t4 = time.time()print('爬虫用时'.center(20, '='))print('登录用时{}秒\n'.format(t2-t1))print('解析用时{}秒\n'.format(t3-t2))print('下载{}张图片用时{}秒\n'.format(len(pic_list), t4-t3))print('完成'.center(20, '='))

selenium爬取Ajax加载的网页(以微博为例)相关推荐

  1. python爬虫动态加载页面_Python+Selenium爬取动态加载页面(2)

    注: 上一篇<Python+Selenium爬取动态加载页面(1)>讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网.数据的获取过程跟人手动获取过程类似,所 ...

  2. java.lang.NoClassDefFoundError:org/apache/commons/io/Charsets (jsoup配合htmlunit 爬取异步加载的网页遇到的)

    最近用jsoup配合htmlunit 爬取异步加载的网页运行代码的时候,报错java.lang.NoClassDefFoundError:org/apache/commons/io/Charsets ...

  3. 网络爬虫 | selenium 爬取动态加载信息

    使用selenium实现动态渲染页面的爬取.selenium是浏览器自动测试框架,模拟浏览器,驱动浏览器执行特定的动作,并可获取浏览器当前呈现的页面的源代码,可见即可爬.该工具支持IE浏览器.Mozi ...

  4. Python爬虫爬取Ajax加载的百度图库

    Ajax 是一种用于创建快速动态网页的技术, 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. Ajax用一句话来说就是不需要刷整个新页面即可从服务器取得数据(局部刷新) 今天通过在百度 ...

  5. python selenium 爬取js加载的内容为空,Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容...

    1,引言 在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor.本文记录了确定gsExtractor的技术路线过程中所做的编程实验.这是第二部分,第一 ...

  6. python爬取动态加载的网页之爬取猫眼电影实时票房

    <猫眼电影实时票房>这个网页是通过动态加载的数据,大约4秒钟就要请求一次服务器,上面的数据每次请求都会产生变化,如果直接用requests请求它的html源代码,并获取不了它的数据. 网页 ...

  7. 爬取ajax加载的豆瓣电影

    (一)前提:找到ajax异步加载的包接口,注意第一个电影名 我们把Request URL网址复制到地址栏得到: 上图是json格式数据,且第一个电影一致,说明我们找到了正确的ajax的json接口 出 ...

  8. python requests+json爬取ajax加载 爱彼迎深圳所有房源

    目的: 爬取爱彼迎深圳所有房源的房主,价格,房源介绍等信息 步骤如下: step1:获取房源页面url 登陆爱彼迎网站,搜索深圳房源 https://zh.airbnb.com/s/homes?ref ...

  9. scrapy爬取动态网页_scrapy_splash 爬取 js 加载网页初体验

    最近打算学习 scrapy_splash 来爬取 js 加载的动态网页 selenium 实在太慢了,不在迫不得已的情况下并不推荐使用 下面,直接开始吧 目标网站 JD 某商品 环境需求 已安装 do ...

最新文章

  1. 一文详解科研中的Paper阅读方法!!!
  2. Asp.net网站的自动部署-sqlserver数据库的自动部署
  3. nova-scheduler详解 openstack-ice版
  4. Google 系两公司联手,要让无人车少“犯错”
  5. 【CyberSecurityLearning 70】DC系列之DC-1渗透测试(Drupal)
  6. android ppt下载地址,Microsoft PowerPoint下载
  7. UWP使用AppService向另一个UWP客户端应用程序提供服务
  8. linux安装库文件下载,Linux下的Curses库的下载与安装
  9. 巨星陨落,光芒永存—回顾霍金对人工智能的思考
  10. ES6 Reflect使用笔记
  11. PM_敏捷开发 Scrum vs Kanban,如何选择?
  12. Js页面打印组件实现
  13. [Matlab] norm函数用法(用于RMSE和R2)
  14. 一种计算机显卡保护装置,一种计算机显卡辅助支撑装置制造方法及图纸
  15. matlab中global
  16. Python实战 | 手拉手教你爬取贝壳房源数据
  17. Github访问和下载慢的解决与提升方案
  18. html rfftq15.gif,STM32F4系列完整固件库
  19. iOS开发:苹果开发者账号第一次新建APP ID以及创建App的步骤
  20. 网易163邮箱配置-iOS、OS X邮箱客户端

热门文章

  1. AliOS-Things开发入门
  2. 人工智能基础——贝叶斯分类器例程(c语言实现,完整代码)
  3. 自制网页(仿B站)前端开源程序
  4. ngro_k服务器搭建(本地电脑与微信交互)
  5. PostgreSQL如何实现MVCC (基于xmin、xmax、cmin、cmax)
  6. 电脑快捷键快速打开截图快捷方法
  7. unity 回合制_用Unity E3 Goodness制成
  8. 北斗系统海拔高度测试软件,GPS海拔测量仪手机版
  9. 邓仰东专栏|机器学习的那些事儿(一)
  10. 慕课网懒懒交流会AngularJs专场学习笔记