模拟登陆163邮箱并爬取邮件信息 - Selenium和Mong
2017-10-07 本文已影响486人
马淑
归属文集:Selenium + MongoDB
环境需求
本机环境:32bit Windows + Python3 + Selenium + MongoDB ; FireFox浏览器;Firefox Driver
流程分析
- Selenium模拟输入账号和密码点击登陆163邮箱
- 等待网页加载,模拟点击收件箱获取邮件列表,并爬取初始页
- 模拟点击翻页按钮,爬取分页
- 数据存储至MongoDB
代码实现
注释很详细,直接上代码
import time
from time import sleep
import pymongo
from selenium import webdriver
from bs4 import BeautifulSoup
client = pymongo.MongoClient('localhost', 27017)
db = client['163mail']
collection = db['mymail']
'''以下代码实现数据保存'''
def save_to_db(item):
if collection.insert_one(item):
print('保存成功!')
else:
print('保存失败!')
'''以下代码实现数据提取'''
def parse_item(maillist):
for m in maillist:
long_text = str(m.attrs['aria-label'])
yield {
'e_title':long_text.split('发件人 :')[0].strip(),
'e_sender':long_text.split('发件人 :')[1].split('时间:')[0].strip(),
'e_send_time':long_text.split('发件人 :')[1].split('时间:')[1].strip()
}
'''以下代码实现邮件列表Soup处理'''
def process_soup(soup, Count):
try:
maillist = soup.find_all(attrs={'sign': 'letter'})
for item in parse_item(maillist):
Count += 1
print(Count, item)
save_to_db(item)
except Exception as err:
print(err)
finally:
return Count
'''以下代码实现163邮箱自动登录'''
def login(driver):
# 等待页面完全加载
driver.implicitly_wait(30)
# 因为163登录入口在iframe里面,所以先要切换到iframe
frame = driver.find_element_by_id('x-URS-iframe')
driver.switch_to.frame(frame)
# 使用driver将账号密码填进表单并提交
email = driver.find_element_by_xpath("//input[@name='email']").send_keys('tjmashu')
pwd = driver.find_element_by_xpath("//input[@name='password']").send_keys('***********')
login = driver.find_element_by_id('dologin').click()
return driver
'''以下代码实现163邮箱收件箱 - 初始页邮件爬取'''
def crawl_1st_page(driver, Count):
print('page = ' + '1')
# 点击收件箱按钮加载邮件列表
driver.find_element_by_id('_mail_component_76_76').click()
time.sleep(20)
driver.switch_to.default_content()
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
Count = process_soup(soup, Count)
# 获取总的翻页数
total_page = int(driver.find_element_by_class_name('nui-select-text').text.split('/')[1])
print('total_page = ' + str(total_page))
return [total_page, Count]
'''以下代码实现163邮箱收件箱 - 分页邮件爬取'''
def crawl_other_page(driver, Count):
# 点击下一页按钮加载邮件列表
ele = driver.find_element_by_class_name('nui-toolbar-ext')
this_ele = ele.find_elements_by_class_name('nui-toolbar-item')[-2]
mail_box = this_ele.find_elements_by_tag_name('div')[-1]
mail_box.click()
time.sleep(20)
driver.switch_to.default_content()
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
Count = process_soup(soup, Count)
print('page = ' + str(page + 1) + '分析完成')
return Count
'''主程序'''
if __name__ == '__main__':
Count = 0
# 调用FireFox Driver登陆163邮箱
driver = webdriver.Firefox()
driver.implicitly_wait(30)
driver.get('http://mail.163.com/')
driver = login(driver)
# 等待登陆后的新页面完全加载
time.sleep(20)
# 获取最新的窗口句柄,不然会发生can't access dead object错误
driver.switch_to.default_content()
# 先爬取初始收件箱页面并获取总的页数,再爬取分页页面
total_page, Count = crawl_1st_page(driver, Count)
# 获取每个分页上的邮件列表信息生成对应Soup,每个Soup逐一解析处理
for page in range(total_page):
time.sleep(20)
driver.switch_to.default_content()
if page > 0:
print('page = ' + str(page+1))
Count = crawl_other_page(driver, Count)
运行结果


问题与解决
1. Driver找不到Element错误
原因1:163邮箱页面加载响应时间过长,程序执行查找元素时,该元素还没有被加载
解决1:设置强制等待time.sleep(20)
,隐式等待driver.implicitly_wait(30)
原因2:要查找的内容是在iframe里面时,需要先找到iframe将句柄切换这个iframe
解决2:切换句柄到iframe
# 因为163登录入口在iframe里面,所以先要切换到iframe
frame = driver.find_element_by_id('x-URS-iframe')
driver.switch_to.frame(frame)
原因3:Element是动态ID,没有name属性,driver.find_element_by_id()不可用
解决3:先向上查找到它的父元素,再往下定位要找的子元素,例如本例中向上两级找到了静态id的父元素,再向下回去找子元素
# 点击下一页按钮加载邮件列表
ele = driver.find_element_by_class_name('nui-toolbar-ext')
this_ele = ele.find_elements_by_class_name('nui-toolbar-item')[-2]
mail_box = this_ele.find_elements_by_tag_name('div')[-1]
mail_box.click()
2.页面跳转更新之后,查找元素时报can't access dead object错误
原因:页面跳转更新后,要将句柄切换到新的页面内容
解决:增加语句 driver.switch_to.default_content()
3.出现[WinError 10061] 由于目标计算机积极拒绝,无法连接。

原因:MongoDB服务没有启用!
解决:以管理员身份启用MongoDB,输入:net start MongoDB
启动MongoDB
4.有时候元素明明已经找到了,运行也没报错,点击后页面没任何反应。
网上有人用js方法解决这个问题,参见:http://blog.csdn.net/mufenglin01/article/details/72637043
也有人发现原来是click的时候已经失去该焦点了,解决办法是先找另外的元素,再来找这个元素,例如:
http://blog.csdn.net/aerchi/article/details/8061127