爬取对象

我们的爬取目标是(登陆状况下的)新浪微博的首页。也就是下图:

python爬虫技术分享(Python爬虫进阶五)(1)

爬取目标

首先,我们要模拟登陆。

其次,我们要下拉滚动条两次,让微博加载新的动态。

第三,作为良好公民我会给我关注的所有博主点赞,所以我们给所有微博点一次赞。

第四,我们把获取到的所有博文保存到文件里。

第五,我们发一条微博,内容为“Hello World!”。

那么,我们的上述行为用到了:

python爬虫技术分享(Python爬虫进阶五)(2)

准备工作-分析页面1 模拟登陆

微博的登录按钮对应的html文本如图所示:

python爬虫技术分享(Python爬虫进阶五)(3)

我们使用find_element_by_link_text("登录")获取此元素然后click(ele)点击它。

跳出的登录界面如图:

python爬虫技术分享(Python爬虫进阶五)(4)

因为使用帐号密码登录会有验证码,所以我们直接使用qq登录。在查找元素之前我们还要变更driver指向的窗口为最新的窗口。

python爬虫技术分享(Python爬虫进阶五)(5)

在直接查找qq登录的元素之前我们要先定位进外面的iframe元素,不然会报查找不到。

2 下拉滚动条

直接让selenium运行下拉滚动条的JS就可以,至于滚动像素我们使用document.body.clientHeight获取(这个函数返回body元素的高度,还有一个document.documentElement.clientHeight返回屏幕中可见的高度)。下拉滚动条的JS为Window_scrollBy(right,down)。

3 点赞

获取所有点赞对应的元素(node-type="like_status"),然后依次执行点击操作(记得设置间隔时间)。

4 保存博文

本步骤的原理很简单,即获取所有满足条件的元素然后保存到文件内。但是微博的页面元素较为复杂,我们要保存所有博文的所有内容,也包括图片,并且要把所有折叠的内容展开。

所以我们的步骤分为五步:首先我们要点击页面中的所有“展开全文”,然后获取所有node-type=”feed_list_item”元素,之后遍历确认其是否含有node-type=”feed_list_content_full”或node-type=”feed_list_content”的内容标签,再遍历确认是否含有图片。最后我们根据图片的链接下载图片。

5 发表微博

找到发表微博的textarea,使用sendKeys发送微博内容,然后对提交按钮使用click()。

代码部分

#0️⃣.准备工作----------------------------------------------------------------------------- from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from time import sleep from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import requests DRIVERPATH="chromedriver.exe" driver=webdriver.Chrome(DRIVERPATH) driver.get("https://weibo.com/") driver.implicitly_wait(10) #等待加载 #---------------------------------------------------------------------------------------- #1️⃣.登录--------------------------------------------------------------------------------- _handle=driver.current_window_handle #记录当前的句柄 login1=driver.find_element_by_css_selector('[node-type="loginBtn"]') #登录按钮 login1.click() #执行点击动作 点击登录 login2=driver.find_element_by_css_selector('[node-type="qq_box"]') login2.click() #点击切换到qq登陆 #此时,微博会跳出一个新标签页来完成qq登陆,所以我们要切换selenium的句柄 handlel=driver.window_handles while(len(handlel)==1): sleep(1) handlel=driver.window_handles #等待 直到有多个句柄 driver.switch_to.window(handlel[-1]) #切换到新窗口 #但是新的窗口中包含了一个iframe,所以我们还得先定位进frame driver.switch_to.frame("ptlogin_iframe") login3=driver.find_element_by_css_selector('a[uin="2223216740"]') login3.click() #点击头像 登陆 #---------------------------------------------------------------------------------------- #2️⃣.下拉滚动条--------------------------------------------------------------------------- sleep(6) #等待跳转 height=driver.execute_script("return document.body.clientHeight") #获取长度 driver.execute_script("window.scrollTo(0,arguments[0])",height) #下拉 height=driver.execute_script("return document.body.clientHeight")-height driver.execute_script("window.scrollTo(0,arguments[0])",height) #下拉 #--------------------------------------------------------------------------------------- #3️⃣.点赞-------------------------------------------------------------------------------- like=driver.find_elements_by_css_selector('[node-type="like_status"]') #找到所有喜欢的按钮 for i in like: try: driver.execute_script("window.scrollBy(arguments[0])",i) #可视过程,极致享受 i.click() sleep(1) except: driver.find_element_by_css_selector('[node-type="ok"]').click() break #如果提示操作频繁就点掉,然后跳出去 #这里会有个问题,点赞过快或者过多会弹出“操作频繁”页面(有时候我正常浏览都会弹,只能说emmm) #--------------------------------------------------------------------------------------- #4️⃣.保存博文---------------------------------------------------------------------------- text_expand=driver.find_elements_by_link_text("展开全文") for i in text_expand: i.click() #点击所有展开全文 text=driver.find_elements_by_class_name("WB_detail") #找到所有微博正文内容 # #---------------------------------------------------------------------------- # #Weibo类 定义,用于存储微博的内容 # #---------------------------------------------------------------------------- class Weibo: img=[] def setAuthor(self,author): self.author=author def setTime(self,time): self.time=time def setText(self,text): self.text=text def addImg(self,img): self.img.append(img) re=[] #用于存储微博数据的Weibo对象列表 for i in text: try: i.find_element_by_css_selector('[node-type="feed_list_item_date"]') #广告是没有时间的 except: continue a=Weibo() a.setAuthor(i.find_element_by_class_name("WB_info").text) a.setTime(i.find_element_by_css_selector('[node-type="feed_list_item_date"]').get_attribute("title")) if len(i.find_elements_by_css_selector('[node-type="feed_list_content"]'))>0: #不用展开的博文的node-text if len(i.find_elements_by_css_selector('[node-type="feed_list_forwardContent"]'))>0: #注意转发之前是否有引用 a.setText(i.find_element_by_css_selector('[node-type="feed_list_content"]').text i.find_element_by_css_selector('[node-type="feed_list_forwardContent"]').text) else: a.setText(i.find_element_by_css_selector('[node-type="feed_list_content"]').text) elif len(i.find_elements_by_css_selector('[node-type="feed_list_forwardContent"]'))>0: #展开了博文 有前置的情况下 a.setText(i.find_element_by_css_selector('[node-type="feed_list_content_full"]').text i.find_element_by_css_selector('[node-type="feed_list_forwardContent"]').text) else: a.setText(i.find_element_by_css_selector('[node-type="feed_list_content_full"]').text) if len(i.find_elements_by_class_name("media_box")[0].find_elements_by_tag_name("img"))>0: #获取图片 for m in i.find_element_by_class_name("media_box").find_elements_by_tag_name("img"): a.addImg(m.get_attribute("src")) re.append(a) with open("output.txt","w",encoding="utf-8",errors="ignore") as f: for i in re: f.write("作者:" i.author "\n") f.write("时间:" i.time "\n") f.write("内容:" i.text "\n") f.write("图片链接:") for m in i.img: #这里可以用正则表达式直接变成文件名之类的,我们就不详细写了 f.write(m ",") f.write("\n") def getImg(url): imgname=url.spilt("\\")[-1] with open("img/" imgname,'w') as f: f.write(requests.get(i).read()) #用requests是因为快速而且方便 return imgname for i in re: #下载图片 for m in i.img: print(getImg(m) "下载完成。") #--------------------------------------------------------------------------------------- #5️⃣.发布新微博-------------------------------------------------------------------------- driver.find_element_by_css_selector('[node-type="textEL"]').sendKeys("Hello World!") driver.find_element_by_css_selector('[node-type="submit"]').click() #---------------------------------------------------------------------------------------

,