+update 2020-02-11
最近锁王唐唐很厉害啊,甚是迷恋,鄙人观望了小呆的微博已经两天了,路转粉,绝对铁粉,闲来无事,我要开始分析wuli唐唐了。爬取了小呆的新浪微博,赞帖,帖子内容,发帖时间,转发数,评论数,点赞数。其中,不乏入坑无数,然而,都一一克服了,不得不说,这就是小呆的力量。
1. 模拟人类自动登录记住cookie
1.1 捕获当前所有窗口
在这里,不得不说,新浪微博的爬取并非易事。
首先,进入"https://weibo.com/”的登录页面,自动化介入,点击“登录”的同时,网页跳转了,此时,需要捕捉当前所有窗口。
handles = browser.window_handles #获取当前打开的所有窗口的句柄
1.2 页面跳转/窗口切换
捕获全部窗口,锁定当前窗口。
browser.switch_to.window(handles[1]) #切换到第二个窗口的句柄
print(browser.current_window_handle)
print(browser.current_url)
1.3 iframe窗口解决自动登录
经过无数次xpath的元素定位查找,总是出现NoSuchElementException,并未能解决,经过查阅大量资料,无意中发现iframe类型,查看原码,发现该登陆窗口是iframe形式,大喜!
browser.implicitly_wait(5)
#先找到到iframe(id )
browser.switch_to_frame("ptlogin_iframe")
browser.find_element_by_xpath('//*[@id="qlogin_list"]/a[1]').click()
定位并点击进行登陆,需要说明,这里我是通过扣扣注册的新浪微博,同时需要把扣扣登陆上。
1.4 搜索框自动搜索
定位并点击搜索,接下来就是一些列的自动click,直到进入目标任务的主页。
browser.implicitly_wait(5)
search = browser.find_element_by_xpath('//*[@id="plc_top"]/div/div/div[2]/input').send_keys("唐禹哲")
browser.find_element_by_xpath('//*[@id="plc_top"]/div/div/div[2]/a').click()
需要保留cookie的保留,下次直接cookie就可以。
同时,在爬取过程中,页面加载可能需要时间,此时,需要设置等待时间。
2. 异步加载
新浪微博的页面比较特殊,需要大概三次拖拽方可将第一页加载完全,其他页也是一样,找了很多selenium异步加载的文章都未能解决问题,直到遇到下面的解决方案。何为异步加载,当滑到底部,页面出现待加载的内容。
time.sleep(10)
def selenuim_loading_more(browser, method_index=0):
if method_index==0:
browser.implicitly_wait(3) # 为了快速滑动,先设置超时时间为3秒
# while True:
for i in range(1, 4): # at most 3 times
print("loading more, window.scrollTo bettom for the", i,"time ...")
browser.execute_script("window.scrollTo(0,document.body.scrollHeight);")
try:
# 定位页面底部的换页tab
browser.find_element_by_css_selector("div[class='W_pages']")
break # 如果没抛出异常就说明找到了底部标志,跳出循环
except :
pass # 抛出异常说明没找到底部标志,继续向下滑动
browser.implicitly_wait(4) # 将超时时间改回10秒
elif method_index==1:
browser.find_element_by_css_selector("div[class='empty_con clearfix']").click() # loading more
print("loading more, sleep 4 seconds ... 1")
time.sleep(4)
browser.find_element_by_css_selector("div[class='empty_con clearfix']").click() # loading more
print("loading more, sleep 3 seconds ... 2")
time.sleep(2)
elif method_index==2:
load_more_1 = browser.find_element_by_css_selector("div[class='empty_con clearfix']") # loading more
ActionChains(browser).click(load_more_1).perform()
print("loading more, sleep 4 seconds ... 1")
time.sleep(4)
load_more_2 = browser.find_element_by_css_selector("div[class='empty_con clearfix']") # loading more
ActionChains(browser).click(load_more_2).perform()
print("loading more, sleep 3 seconds ... 2")
time.sleep(2)
elif method_index==3:
print("loading more, sleep 4 seconds ... 1")
element = WebDriverWait(browser, 4).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class='empty_con clearfix']"))
)
element.click()
print("loading more, sleep 2 seconds ... 2")
WebDriverWait(browser, 2).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class='empty_con clearfix']"))
).click()
return browser
browser = selenuim_loading_more(browser, method_index=0)
ok !异步加载问题的解决就真的解决了多数了,下面就是元素定位问题。
3. selenium元素定位
最简单的额一种方法就是通过选定找到xpath,而xpath的语法又有很多种,
第一种是通过制定contains
browser.find_elements_by_xpath('//div[contains(@class,"WB_info")]//a[contains(@href,"//weibo.com/")]')
第二种是全部路径形式
browser.find_element_by_xpath('//*[@id="Pl_Official_MyProfileFeed__21"]/div/div[{0}]/div[2]/div/ul/li[2]/a/span/span/span/em[2]'.format(i+1))
这样的话,可能是点赞的文章与自己发的帖子的xpath路径不同,就需要设置判断语句来进行不同的操作。
其他方法也有很多,这里就用了两种,其他方法,自行搜索。
4. 异常报错判断
在爬虫过程中,需要增加相应的异常判断,否则,爬了半天,发现最后报错了,那就简直*了狗了,心中一万只你懂得!
常用的异常判断,无非就是try except
from requests.exceptions import ReadTimeout,HTTPError,ConnectionError,RequestException
from selenium.common.exceptions import NoSuchElementException
try:
weibo_content.append(browser.find_element_by_xpath('//*[@id="Pl_Official_MyProfileFeed__21"]/div/div[{0}]/div[2]/div[3]/div[4]'.format(i+1)).text)
except NoSuchElementException:
weibo_content.append(browser.find_element_by_xpath('//*[@id="Pl_Official_MyProfileFeed__21"]/div/div[{0}]/div[2]/div[4]/div[4]'.format(i+1)).text)
5. 关闭弹窗类alert
代码中使用如下信息提示:selenium.common.exceptions.UnexpectedAlertPresentException
错误,经查询,这类弹窗需要去了方可继续。
driver.find_element_by_xpath(".//*[@id='bg-nested-dropdown']")
try:
driver.switch_to.alert.accept()
print 'have switch_to-alert'
print '----bullet window has been clicked'
except:
print 'no alert'
elem = driver.find_element_by_xpath(".//*[@id='bg-nested-dropdown']")
这里也就列举了几种,其他的需要自己查阅。