Selenium是自动化测试常用的实现模块,但其的应用不仅仅局限在于自动化测试,这里介绍Selenium+WebDriver实现数据爬取。
需求分析
1.使用Selenium+WebDriver访问斗鱼平台英雄联盟页面,爬取当前所有直播用户的房间名和观众人数。
2.使用MongoDB实现所爬取数据的保存。
页面分析
- 创建一个douyuSpider.py的文件,导入selenium模块并实例化一个webdriver对象。
from selenium import webdriver
driver = webdriver.Chrome()
- 定义斗鱼英雄联盟专区的url,访问该链接。
driver .get("https://www.douyu.com/g_LOL")
# 最大化窗口
driver.maximize_window()
-
对必要元素进行定位。
1.定位直播房间名元素
2.定位观众人数元素
3.定位“下一页”元素
# 定位到直播房间名在class="layout-Cover-list"的一个子孙标签h3里 names = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
# 这个names是一个列表,里面的内容是该页面所有直播用户房间名所对应的标签元素
# 定位到观众人数在class="DyListCover-hot"的span标签里
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
# 这个numbers是一个列表,里面的内容是该页面所有直播用户观众数量所对应的标签元素
# 定位到下一页在class="dy-Pagination-next"的li标签里
driver.find_element_by_class_name('dy-Pagination-next').click()
我们想通过循环来不断点击下一页来获取各个页面的数据,那么如何判定循环结束呢?不妨把关注点放在下一页定位到的那个li标签上。
# 第一页对应的li标签
# <li title="下一页" tabindex="0" class=" dy-Pagination-next" aria-disabled="false"><span class="dy-Pagination-item-custom">下一页</span></li>
# 第二页对应的li标签
# <li title="下一页" tabindex="0" class=" dy-Pagination-next" aria-disabled="false"><span class="dy-Pagination-item-custom">下一页</span></li>
# 最后一页对应的li标签
# <li title="下一页" class="dy-Pagination-disabled dy-Pagination-next" aria-disabled="true"><span class="dy-Pagination-item-custom">下一页</span></li>
我们会惊喜地发现li标签的aria-disabled属性值从false变为了true,可以以此为标志作为循环的结束。
# 循环结束的标志为
driver.find_element_by_class_name('dy-Pagination-next').get_attribute("aria-disabled") != 'false'
# .get_attribute("属性")可以获取属性对应的值
函数封装
上面的分析可以分为三部分,我们可以对其进行一下简单的封装,使代码更加清晰。
# 请求访问
def get_url():
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.douyu.com/g_LOL")
sleep(1) # 设置1秒等待,用于加载元素,避免获取不到定位元素
return driver
# 打印单页
def print_onepage(driver):
titles = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
for title,number in zip(titles,numbers):
print(u"观众人数:"+number.text.strip()+u"\t房间名:"+title.text.strip())
# 循环打印
def print_allpage(driver):
while driver.find_element_by_class_name('dy-Pagination-next').get_attribute("aria-disabled") == 'false':
print_onepage(driver)
driver.find_element_by_class_name('dy-Pagination-next').click()
sleep(1)
driver.quit()
查看打印效果
我们先导入对应的库,打印单页看看效果是否符合预期。
from selenium import webdriverfrom time
import sleep
def get_url():
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.douyu.com/g_LOL")
sleep(1) # 设置1秒等待,用于加载元素,避免获取不到定位元素
return driver
def print_onepage(driver):
titles = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
for title,number in zip(titles,numbers):
print(u"观众人数:"+number.text.strip()+u"\t房间名:"+title.text.strip())
driver.quit()
if __name__ == "__main__":
driver = get_url()
print_onepage(driver)
显然,打印结果是符合预期的。现在可以尝试打印所有页面。
from selenium import webdriver
from time import sleep
def get_url():
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.douyu.com/g_LOL")
sleep(2) # 设置1秒等待,用于加载元素,避免获取不到定位元素
return driver
def print_onepage(driver):
titles = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
for title,number in zip(titles,numbers):
print(u"观众人数:"+number.text.strip()+u"\t房间名:"+title.text.strip())
def print_allpage(driver):
while driver.find_element_by_class_name('dy-Pagination-next').get_attribute("aria-disabled") == 'false':
print_onepage(driver)
driver.find_element_by_class_name('dy-Pagination-next').click()
sleep(1)
driver.quit()
if __name__ == "__main__":
driver = get_url()
print_allpage(driver)
保存数据
这里使用pymongo模块将数据保存到MongoDB数据库。
- 使用mongo在命令行打开数据库,查看端口地址。
- 导入pymongo模块,并实例化数据库。
import pymongo
client = pymongo.MongoClient('mongodb://127.0.0.1:27017')# 端口地址
collection = client["douyu"]["LOL"] # 建立一个douyu的库,并在其下面建立一个叫LOL的集合
- 保存数据到MongoDB数据库。
def store_onepage(i,driver):
titles = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
for title,number in zip(titles,numbers):
# print(u"观众人数:"+number.text.strip()+u"\t房间名:"+title.text.strip())
data = {}
data['观众人数'] = number.text.strip()
data['房间名'] = title.text.strip()
collection.insert_one(data)
print("第%d页保存完毕!"%i)
def store_allpage(driver):
i = 1
while driver.find_element_by_class_name('dy-Pagination-next').get_attribute("aria-disabled") == 'false':
store_onepage(i,driver)
i += 1
driver.find_element_by_class_name('dy-Pagination-next').click()
sleep(1)
driver.quit()
- 完整代码
import pymongo
from selenium import webdriver
from time import sleep
client = pymongo.MongoClient('mongodb://127.0.0.1:27017')# 端口地址
collection = client["douyu"]["LOL"] # 建立一个douyu的库,并在其下面建立一个叫LOL的集合
def store_onepage(i,driver):
titles = driver.find_elements_by_xpath('//ul[@class="layout-Cover-list"]//h3')
numbers = driver.find_elements_by_xpath('//span[@class="DyListCover-hot"]')
for title,number in zip(titles,numbers):
# print(u"观众人数:"+number.text.strip()+u"\t房间名:"+title.text.strip())
data = {}
data['观众人数'] = number.text.strip()
data['房间名'] = title.text.strip()
collection.insert_one(data)
print("第%d页保存完毕!"%i)
def store_allpage(driver):
i = 1
while driver.find_element_by_class_name('dy-Pagination-next').get_attribute("aria-disabled") == 'false':
store_onepage(i,driver)
i += 1
driver.find_element_by_class_name('dy-Pagination-next').click()
sleep(1)
driver.quit()
if __name__ == "__main__":
driver = get_url()
store_allpage(driver)
- 保存效果展示