需求:
博主之前有一段時(shí)間突然不想玩微博了,然后正好表弟想玩呼畸,就給他用了痕支,手機(jī)綁定也換成了他的號(hào)碼。近期突然又想要玩蛮原,就重新開了個(gè)號(hào)卧须。新號(hào)微博空空的徒河,也沒有什么關(guān)注灌砖。于是就產(chǎn)生了兩個(gè)需求,正好可以借這個(gè)機(jī)會(huì)學(xué)習(xí)一下自動(dòng)化測試工具webdriver的基本使用:
1誊酌、將原微博的博文搬到新賬號(hào)
2蹦漠、用新賬號(hào)關(guān)注原微博的所有關(guān)注
說明:
這一篇是python爬蟲入門 實(shí)戰(zhàn)(五)---用webdriver實(shí)現(xiàn)批量自動(dòng)發(fā)微博的姊妹篇椭员,實(shí)現(xiàn)的是第二個(gè)需求,我們繼續(xù)來學(xué)習(xí)webdriver的使用笛园。
涉及:
使用webdriver實(shí)現(xiàn):
1隘击、尋找單個(gè)元素(element)
2、尋找一組具有相同屬性的元素
3研铆、點(diǎn)擊按鈕
4闸度、獲取元素的屬性
5、獲取元素包含的文本
本篇目錄:
1.思路
2.登錄微博
3.進(jìn)入目標(biāo)用戶關(guān)注列表蚜印,獲取未關(guān)注用戶id莺禁。
4.利用獲取到的id進(jìn)入目標(biāo)博主主頁,進(jìn)行關(guān)注操作
5.完整代碼
6.效果演示動(dòng)圖
7.參考
思路:
1窄赋、登錄微博
2哟冬、進(jìn)入目標(biāo)用戶(博主原微博)關(guān)注列表,獲取未關(guān)注用戶id
3忆绰、利用獲取到的id進(jìn)入目標(biāo)博主主頁浩峡,進(jìn)行關(guān)注操作
登錄微博
在上一篇教程python爬蟲入門 實(shí)戰(zhàn)(五)---用webdriver實(shí)現(xiàn)微博“搬家”(1)里的第三部分【用webdriver啟動(dòng)瀏覽器登錄微博】有思路和代碼的詳細(xì)說明。此篇不再贅述错敢。
進(jìn)入目標(biāo)用戶關(guān)注列表翰灾,獲取未關(guān)注用戶id缕粹。
1、先手動(dòng)登錄微博纸淮,進(jìn)入到目標(biāo)用戶的關(guān)注列表平斩,觀察url鏈接的構(gòu)造:
http://weibo.com/p/1005052622535523/follow?from=page_100505&wvr=6&mod=headfollow#place
1、咽块?后的參數(shù)并不重要可以直接刪去绘面,重新加上 page 參數(shù)可以指定頁碼。
2侈沪、p/后的那串?dāng)?shù)字是100505+‘用戶 id ’
所以我們可以登錄以后揭璃,用一個(gè)循環(huán)遍歷所有的頁碼數(shù)構(gòu)造 url 鏈接,用
driver.get 方法訪問亭罪,即可訪問所有的關(guān)注列表瘦馍。
2、接下來看如何獲取一頁列表中所有的未關(guān)注用戶的 id 应役。
定位到【關(guān)注】按鈕情组,發(fā)現(xiàn)可以找到我們要的用戶 id (即圖中紅框里的 “uid” )。所以扛吞,我們只要找到這個(gè)元素獲取它的 “action-data” 屬性呻惕,用字符串切割和切片即可得到用戶 id 字符串。
另外滥比,我們只需關(guān)注未關(guān)注的用戶亚脆,所以已關(guān)注用戶的 id 我們是不需要的。再定位到【已關(guān)注】按鈕盲泛,對比兩個(gè)元素的屬性差異濒持。如下兩個(gè)截圖:
我們可以發(fā)現(xiàn)它們都有 “action-type” 這個(gè)屬性,而且不同寺滚。所以我們可以用這個(gè)屬性來區(qū)分未關(guān)注用戶和已關(guān)注用戶柑营。思路總結(jié)成一句話就是,找到本頁中所有
action-type="follow" 的 a 標(biāo)簽村视,獲取 “action-data” 屬性并截取其中的 uid 官套。
因?yàn)榉?hào)條件的元素有多個(gè)(每頁有多個(gè)用戶的關(guān)注按鈕),所以用driver.find_elements(注意蚁孔,比上篇教程中的方法 driver.find_element 多一個(gè) “s”奶赔,返回的是 list )來查找一組目標(biāo)元素。用 element.get_attribute 來獲取目標(biāo)屬性杠氢。
獲取用戶 id 的代碼如下:
# 獲取某用戶的關(guān)注列表中 登錄用戶未關(guān)注的用戶
def get_followlist_unf(self,uid,page):
url='http://weibo.com/p/100505'+uid+'/follow'+'?page='+str(page)# 關(guān)注列表頁
self.driver.get(url)
a_list=self.driver.find_elements_by_xpath('//a[@action-type="follow"]')# 找到所有的關(guān)注按鈕上的 a 標(biāo)簽元素
uid_list=[]
for a in a_list:
action_data=a.get_attribute('action-data')# 獲取 action-data 屬性
uid=action_data.split('&')[-3].split('=')[1]# 獲取uid的值
uid_list.append(uid)# 將uid加入到list中
return uid_list # 返回本頁所有的uid
action_data 屬性例子 :
action-data="refer_sort=followlist&refer_flag=followlist&uid=1785997537&fnick=黃思琦-&f=1"
獲取 uid 的那一行站刑,是將 action_data 屬性的字符串值從‘&’符號(hào)分割,[-3]索引到分割結(jié)果的倒數(shù)第三個(gè)鼻百,獲得字符串 uid="用戶id"绞旅,再從“=”分割摆尝,[1]索引到分割結(jié)果的第二個(gè),也就是 uid 的值因悲。
利用獲取到的id進(jìn)入目標(biāo)博主主頁堕汞,進(jìn)行關(guān)注操作
**1、手動(dòng)進(jìn)入一個(gè)未關(guān)注用戶的主頁囤捻,查看 url 結(jié)構(gòu)臼朗。如下圖: **
http://weibo.com/u/2392717877?refer_flag=1005050006_&is_hot=1
1邻寿、同樣的蝎土,?后面的參數(shù)沒有用绣否,可以直接刪除不用誊涯。
2、u/后面就是用戶的id
3蒜撮、有些用戶可能有個(gè)性域名暴构,地址與普通用戶不一樣,但是沒關(guān)系段磨,用 id 構(gòu)造的 url (如以上)一樣可以訪問到用戶主頁取逾。
2、找到【關(guān)注】按鈕苹支,進(jìn)行點(diǎn)擊砾隅。
我們定位到【關(guān)注】按鈕,對應(yīng)的元素是一個(gè) div 下的 a 標(biāo)簽债蜜,這個(gè) div 具有屬性 node-type="focusLink"晴埂,所以我們可以用 xpath語法定位到這個(gè)元素⊙岸ǎ回顧xpath語法參考XPath 教程儒洛。
關(guān)注操作的代碼如下:
driver.get('http://weibo.com/u/'+uid)
focuslink=driver.find_element_by_xpath('//div[@node-type="focusLink"]/a')
focuslink.click()
像上一篇教程說的一樣,需要用 WebDriverWait(driver,10) 方法等待加載(10是超時(shí)時(shí)間狼速,可以替換成其他值)琅锻。具體使用可以參考上一篇教程,或者Python selenium 三種等待方式詳解 和 WebDriverWait等設(shè)置等待時(shí)間和超時(shí)時(shí)間這兩篇向胡。
所以第二行改為:
focuslink=WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath('//div[@node-type="focusLink"]/a'))
3恼蓬、點(diǎn)擊了關(guān)注以后,有兩種情況需要處理捷枯。
第一種:關(guān)注成功
第二種:請輸入驗(yàn)證碼
這兩種情況可以通過定位彈出浮窗的標(biāo)題頭來區(qū)別滚秩,定位到標(biāo)題頭:
所以我們只需要用driver.find_element_by_class_name方法來定位到該元素,再用element.get_attribute("innerHTML")來獲取元素的包含文本淮捆。
進(jìn)一步根據(jù)這個(gè)文本進(jìn)行判斷即可郁油,如果成功本股,可以什么都不做,或者輸出成功提示桐腌,如果需要輸入驗(yàn)證碼拄显,因?yàn)閷τ诔鯇W(xué)者過于復(fù)雜,我們不進(jìn)行破解案站,等待兩分鐘后再次調(diào)用關(guān)注該用戶的方法進(jìn)行重試躬审。(經(jīng)過嘗試,一般等待2~5分鐘再關(guān)注即不會(huì)彈出驗(yàn)證碼蟆盐,下次碰到驗(yàn)證碼承边,同樣進(jìn)行等待。)
代碼如下:
def follow(self,uid):
self.driver.get('http://weibo.com/u/'+uid)
focuslink=WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath('//div[@node-type="focusLink"]/a'))
focuslink.click()
# 點(diǎn)完關(guān)注后石挂,檢查頁面是否有需要輸入驗(yàn)證碼博助,如果有的話,等待2分鐘重新關(guān)注該用戶
try:
title=WebDriverWait(driver,10).until(lambda x:x.find_element_by_class_name('W_layer_title'))
title_txt=title.get_attribute('innerHTML')
if title_txt==u'關(guān)注成功':
print u'關(guān)注用戶:'+uid+u' 成功痹愚!'
elif title_txt==u'請輸入驗(yàn)證碼':
print u'需要輸入驗(yàn)證碼富岳,等待120s……'
time.sleep(120)# 休息兩分鐘再試一次
print u'等待結(jié)束,重試'
self.follow(uid)# 再次調(diào)用本方法
except:
pass
這里加了一個(gè) try 和 except拯腮,是為了應(yīng)對什么浮窗都不彈出窖式,找不到標(biāo)題元素的情況,如果找不到即視為已成功關(guān)注动壤,什么都不做萝喘,pass掉即可。
由于有些用戶的關(guān)注列表里有城市的主頁狼电,這些城市主頁的 uid 比較特殊蜒灰,拼接成之前的用戶主頁 url 后會(huì)跳轉(zhuǎn)到主頁面 home ,為了應(yīng)對這種情況肩碟,我們還需要一個(gè) try 和 except 來防止找不到【關(guān)注】按鈕的情況强窖,同樣的,找不到關(guān)注按鈕(即異常)削祈,我們什么都不做翅溺,直接pass掉,不關(guān)注城市主頁髓抑。
修改后的代碼見完整代碼部分咙崎。
以上是關(guān)注一個(gè)用戶的操作,批量關(guān)注即遍歷之前獲取到的用戶id的list吨拍,循環(huán)調(diào)用這個(gè)方法即可褪猛。
完整代碼:
相關(guān)代碼已上傳github:py_study
weibo_op_driver模塊在項(xiàng)目中的weibo文件夾中。
1羹饰、weibo_op_driver模塊中的爬取關(guān)注列表的方法:
# 獲取某用戶的關(guān)注列表中 登錄用戶未關(guān)注的用戶
def get_followlist_unf(self,uid,page):
url='http://weibo.com/p/100505'+uid+'/follow'+'?page='+str(page)# 關(guān)注列表頁
self.driver.get(url)
a_list=self.driver.find_elements_by_xpath('//a[@action-type="follow"]')# 找到所有的關(guān)注按鈕上的 a 標(biāo)簽元素
uid_list=[]
for a in a_list:
action_data=a.get_attribute('action-data')# 獲取 action-data 屬性
uid=action_data.split('&')[-3].split('=')[1]# 獲取uid的值
uid_list.append(uid)# 將uid加入到list中
return uid_list # 返回本頁所有的uid
2伊滋、weibo_op_driver模塊中的關(guān)注與批量關(guān)注方法:
# 關(guān)注用戶
def follow(self,uid):
self.driver.get('http://weibo.com/u/'+uid)
try:
focuslink=self.wait.until(lambda x:x.find_element_by_xpath('//div[@node-type="focusLink"]/a'))
focuslink.click()
# 點(diǎn)完關(guān)注后碳却,檢查頁面是否有需要輸入驗(yàn)證碼,如果有的話笑旺,等待2分鐘重新關(guān)注該用戶
try:
title=self.wait.until(lambda x:x.find_element_by_class_name('W_layer_title'))
title_txt=title.get_attribute('innerHTML')
if title_txt==u'關(guān)注成功':
print u'關(guān)注用戶:'+uid+u' 成功昼浦!'
elif title_txt==u'請輸入驗(yàn)證碼':
print u'需要輸入驗(yàn)證碼,等待120s……'
time.sleep(120)# 休息兩分鐘再試一次
print u'等待結(jié)束筒主,重試'
self.follow(uid)
except:
pass
except:
pass
# 批量關(guān)注(參數(shù)可能包含自身id)
def follow_uidlist(self,uid_list):# 參數(shù)為uid的一個(gè)list
for uid in uid_list:
if uid==self.uid_login:# 如果是自己的id关噪,跳過
continue
# 是未關(guān)注用戶,則關(guān)注
self.follow(uid)
3乌妙、主方法代碼:
operator=WBoperator()
operator.login('account', 'password')# 填入你的微博賬號(hào)密碼
for i in range(41):# 博主原微博有41頁的關(guān)注列表
page=i+1# 頁碼
uid_list_unf=operator.get_followlist_unf('2622535523', page)
operator.follow_uidlist(uid_list_unf)
print u'第'+str(page)+u'頁關(guān)注完畢使兔!'
效果演示動(dòng)圖
參考
XPath 教程
Python selenium 三種等待方式詳解
WebDriverWait等設(shè)置等待時(shí)間和超時(shí)時(shí)間