自己想看一本网络小说但是网络上没有可以直接下载的txt格式文件到我的kindle上,于是想写个爬虫。使用python-selenium工具。
0、前提:已经安装好了python环境,包括环境变量。
1、下载selenium包。
打开命令窗口,输入pip install selenium,即可安装好selenium包
2、下载浏览器驱动。
下载地址:http://chromedriver.storage.googleapis.com/index.html
根据自己浏览器对应的版本下载对应的驱动,例如我的浏览器版本是80.0.3**。引擎放在自己的爬虫文件的同一目录下即可。
3、selenium包的一些基本操作(以下内容复制于自己编辑的有道云笔记,复制过来格式有些乱,可移步过去,要有人看我就把笔记整理好放到csdn上)
http://note.youdao.com/noteshare?id=08cd1afbe098849ca5e097a50061d28e
from selenium import webdriver
wd = webdriver.Chrome('驱动位置')
0、创建驱动获取当前页面信息
wd.get('www.baidu.com')
wd.title #标题
wd.window_handles #所有的窗口
wd.current_window_handle #当前页面的窗口
wd.current_url #当前页面的url
wd.maximize_window() 最大话页面
1、查找元素
wd.find_element_by_id('name') #从元素ID查找
wd.find_elements_by_class_name('name') #从元素CLASS名查找
wd.find_elements_by_tag_name('name') #从元素TAG名查找(tag为尖括号后第一项)
2、操作
2.1 常规操作
element.send_keys('message') #输入新字符串
element.click() #点击
element.clear() #清除输入框已有的字符串
element.get_attribute('class') #'value'#input输入框的文本内容
#'outerHTML'#整个HTML文本内容
#'innerHTML'#内部 的HTML文本内容
#'innerText'or'textContent'#未展
#示内容
2.2 高级操作,详情见附录2
from selenium.webdriver.common.action_chains import ActionChains as AC
ac = AC(webdrive对象)
ac.move_to_element(需要移动的位置).perform() #模拟光标移动
3、CSS选择(一下方法可混用)
find_element_by_css_selector
3.1css查找
3.2'.'前缀代表查找class
3.3)'#'前缀代表查找id
3.4无前缀代表查找tag
3.5元素1 > 元素2 代表查找元素1的直接子元素2(可多个>)
3.6元素1 元素2 代表查找元素1的后代元素2(可多个空格)
3.7以上3.5和3.6可混用
3.8.1'[att = "val"]' 代表查找属性stt的值为val的元素
3.8.2'[att]' 代表有属性stt的元素,不需要知道值为多少
3.8.3'E[stt = "val"]' 代表查找属性stt的值为val的E元素(中间不能有空格)
3.8.4 E,F 同时匹配所有E元素或F元素,逗号的优先级比其他的符号低
3.9.1 :nth-child(2) 代表查找父元素的第2个节点的元素/ :nth-last-child(1)为父元素最后1个元素 / 前可加tag类型 例: p:nth-child(2)
3.9.2 p:nth-of-type(1) 子元素中tag类型为p的第一个元素/ 倒数 p:nth-last-of-type(1) /参数可以是odd or even 表示奇数或偶数,3.9.1相同
3.10 E + F 查找元素E后紧跟的元素F(E,F为tag类型)
3.11 E ~ F 查找元素E后所有的元素F(E,F为tag类型)
3.12 [href*="str"] 其中*=表示包含str
3.13 [href^="str"] 其中^=表示以str开头
3.14 [href$="str"] 其中$=表示已str结尾
4、定位html中document
wd.switch_to.frame(iframe定位点)
wd.switch_to.default_content() #定位到外层
wd.switch_to.window(wd.window_handles[-1]) #切换到最新窗口
5、timesleep(三种方式)
5.1
import time
time.sleep(3)
5.2
from selenium import webdriver
wd.implicitly_wait(5)
6.3 EC包的内容要好好研究需要放入元组
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(wd, 5).until(EC.presence_of_element_located(( By.CSS_SELECTOR, '.login iframe')))
6、选择框
6.1 radio选择框(圆点选择框)<input type="radio"> #直接click需要选择的那个选项即可
6.2 checkbox选择框(勾选、多选框)<input type="checkbox"> #先把已选择的选项全部click,再click需要选择的选项
6.3.1 select选项框(下拉框单选,列表框多选)<select (multiple)> #用以下三种方式选择或取消选择 /(de)select_by_value('str') 选择属性中value值为str的选项 /(de)select_by_visible_text('str') 选择可见文本内容的选项 /(de)select_by_index(num) 选择第n个选项 /deselect_all() 为取消选择所有已选择框
6.3.2 from selenium.webdriver.support.ui import Select #导入select类
select = Select(select元素的定位点) #实例化
select.(以上7.3.1中的几种方法) #使用
7、弹出对话框(浏览器源生对话框,对于html的对话框不能用以下方法)
7.1 alert 通知型对话框
driver.switch_to.alert.accept() #点击对话框中的确认按钮
driver.switch_to.alert.text #获取对话框中的文本内容
7.2 confirm 确认型对话框
点确认、获取文本内容与7.1一样
driver.switch_to.alert.dismiss() #点击对话框中的取消按钮
7.3 prompt 输入型对话框
点确认取消、获取文本与7.2一样
driver.switch_to.alert.send_keys('str') #输入文本str
8、Xpath选择(部分场景Xpath比css好用,或只能用Xpath)(一下方法可混用)
8.1 driver.find_elements_by_xpath("xpath方法")
8.2 “/”为绝对路径选择,例如:/html/body/div 等价于css中 ‘>’
8.3 “//div//p” 所有元素为div的元素下的所有p节点
8.4 “*”为通配符,表示任意tag类型
8.5 [@属性名='属性值'] 表示查找特定元素与元素值的节点 例如://*[@id='str'] xpath中所有属性均用这种方法。查找class时,class一定要写全
8.6 [contain(@classname,'str')] 表示属性中包含str
8.7 [starts-with(@classname,'str')] 表示属性以str开头
8.8 [end-with(@classname,'str')] 表示属性以str结尾
8.9 //p[2] 表示同级节点中第二个p类型节点,类似3.9.2 # //*[2]表示第2个元素 # //p[last() - 1] 表示p类型的倒数第2个元素
8.10 //div[position()<=2] 表示选取前两个div节点
8.11 ‘|’ 表示或的意思,类似3.8.4
8.12 ‘/..’表示选择父节点 //*[@id='father']/.. 表示id为father的父节点(该方法css中不具备)
8.13 /following-sibling::* 表示后续所有兄弟节点 /preceding-sibling::* 表示前序所有兄弟节点
8.14 在某个路径中用xpath查找元素时,查找语句前一定要家上'.',否则从最外层路径查找
-1、小技巧:冻结窗口
在开发者工具栏console执行js代码: setTimeout(function(){debugger},5000) #过5s后执行debugger操作,可冻结窗口。在页面隐藏的情况下用于查找元素比较方便。
附录1(css语法)
*
通用元素选择器,匹配任何元素
E
标签选择器,匹配所有使用E标签的元素
.info
class选择器,匹配所有class属性中包含info的元素
#footer
id选择器,匹配所有id属性等于footer的元素
E,F
多元素选择器,同时匹配所有E元素或F元素,E和F之间用逗号分隔
E F
后代元素选择器,匹配所有属于E元素后代的F元素,E和F之间用空格分隔
E > F
子元素选择器,匹配所有E元素的子元素F
E + F
毗邻元素选择器,匹配紧随E元素之后的同级元素F (只匹配第一个)
E ~ F
同级元素选择器,匹配所有在E元素之后的同级F元素
E[att='val']
属性att的值为val的E元素 (区分大小写)
E[att^='val']
属性att的值以val开头的E元素 (区分大小写)
E[att$='val']
属性att的值以val结尾的E元素 (区分大小写)
E[att*='val']
属性att的值包含val的E元素 (区分大小写)
E[att1='v1'][att2*='v2']
属性att1的值为v1,att2的值包含v2 (区分大小写)
E:contains('xxxx')
内容中包含xxxx的E元素
E:not(s)
匹配不符合当前选择器的任何元素
附录2(Action包内的函数)
click(on_element=None) ——单击鼠标左键
click_and_hold(on_element=None) ——点击鼠标左键,不松开
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None) ——双击鼠标左键
drag_and_drop(source, target) ——拖拽到某个元素然后松开
drag_and_drop_by_offset(source, xoffset, yoffset) ——拖拽到某个坐标然后松开
key_down(value, element=None) ——按下某个键盘上的键
key_up(value, element=None) ——松开某个键
move_by_offset(xoffset, yoffset) ——鼠标从当前位置移动到某个坐标
move_to_element(to_element) ——鼠标移动到某个元素,悬停但不点击
move_to_element_with_offset(to_element, xoffset, yoffset) ——移动到距某个元素(左上角坐标)多少距离的位置
perform() ——执行链中的所有动作
release(on_element=None) ——在某个元素位置松开鼠标左键
send_keys(*keys_to_send) ——发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send) ——发送某个键到指定元素
4、封装一个爬虫(亲测可用,爬下一本小说)
import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
# from selenium.webdriver.support.ui import Select
class WebTools(object):
def __init__(self):
pass
# 打开浏览器
def openbrowser(self, type_name = 'Chrome'):
if type_name == 'Chrome':
self.driver = webdriver.Chrome()
elif type_name == 'Firefox':
self.driver = webdriver.Firefox()
elif type_name == 'IE':
self.driver = webdriver.Ie()
self.driver.maximize_window()
# 跳转页面
def get_web(self, url, time_wait=3):
try:
self.driver.get(url)
except:
print("页面无法打开 ")
self.driver.maximize_window()
if isinstance(time_wait, int):
time.sleep(time_wait)
# 显性等待时间
def webdriverwait(self, maxtime, type_name, value):
element = self.driver.find_element(self.by(type_name), value)
WebDriverWait(self.driver, maxtime).until(ec.presence_of_element_located(element))
# By 函数
def by(self, type):
if type == 'css':
return By.CSS_SELECTOR
if type == 'xpath':
return By.XPATH
if type == 'id':
return By.ID
if type == 'name':
return By.NAME
# 切换到新窗口
def current_handel(self):
self.driver.switch_to.window(self.driver.window_handles[-1])
# 输入内容方法
def input(self, type_name, value, inputvalue):
if type_name == "xpath":
self.driver.find_element_by_xpath(value).send_keys(inputvalue)
elif type_name == "class_name":
self.driver.find_element_by_class_name(value).send_keys(inputvalue)
elif type_name == "id":
self.driver.find_element_by_id(value).send_keys(inputvalue)
elif type_name == "name":
self.driver.find_element_by_name(value).send_keys(inputvalue)
elif type_name == "link_text":
self.driver.find_element_by_link_text(value).send_keys(inputvalue)
elif type_name == "partial_link_text":
self.driver.find_element_by_partial_link_text(value).send_keys(inputvalue)
# 鼠标点击
def click(self, type_name, value):
if type_name == "xpath":
self.driver.find_element_by_xpath(value).click()
elif type_name == "css":
self.driver.find_element_by_css_selector(value).click()
elif type_name == "class_name":
self.driver.find_element_by_class_name(value).click()
elif type_name == "id":
self.driver.find_element_by_id(value).click()
elif type_name == "name":
self.driver.find_element_by_name(value).click()
elif type_name == "link_text":
self.driver.find_element_by_link_text(value).click()
elif type_name == "partial_link_text":
self.driver.find_element_by_partial_link_text(value).click()
# 获取下拉框的文本的值
def get_text(self, type_neme, value):
text = ''
if type_neme == "xpath":
text = self.driver.find_element_by_xpath(value).text
elif type_neme == "css":
text = self.driver.find_element_by_css_selector(value).text
elif type_neme == "name":
text = self.driver.find_element_by_name(value).text
elif type_neme == "link_text":
text = self.driver.find_element_by_link_text(value).text
elif type_neme == "class_name":
text = self.driver.find_element_by_class_name(value).text
elif type_neme == "id":
text = self.driver.find_element_by_id(value).text
return text
# 根据元素获取内容
def get_attribute(self, type_name, value1, value2):
if type_name == "xpath":
value = self.driver.find_element_by_xpath(value1).get_attribute(value2)
return value
elif type_name == "css":
value = self.driver.find_element_by_css_selector(value1).get_attribute(value2)
return value
elif type_name == "name":
value = self.driver.find_element_by_name(value1).get_attribute(value2)
return value
elif type_name == "link_text":
value = self.driver.find_element_by_link_text(value1).get_attribute(value2)
return value
elif type_name == "class_name":
value = self.driver.find_element_by_class_name(value1).get_attribute(value2)
return value
elif type_name == "id":
value = self.driver.find_element_by_id(value1).get_attribute(value2)
return value
# 退出
def quit(self):
self.driver.quit()
MAIN函数
if __name__ == "__main__":
# https://www.sbiquge.com/6_6938/dl :nth-child(1674)
list = []
a = WebTools() # 实例化该方法
a.openbrowser('Chrome') # 使用chrome驱动
a.get_web('https://www.sbiquge.com/6_6938/') # 使用驱动进入该页面
for i in range(0, 1675): # 取出每章节页面的链接,存入list中
http = a.get_attribute('css', 'dl :nth-child(%d)' % i, 'innerHTML')
list.append('https://www.sbiquge.com'+ http.split('\"')[1])
f = open('xxxxxx.txt', mode = 'w', encoding='utf-8')
for web in list: # 逐个打开List中的每个链接,并取出每章节的文本内容,替换不要的文字,
a.get_web(web)
test = a.get_attribute('css', '[id="content"]', 'innerHTML')
title = a.get_text('css', 'h1')
f.write(title + '\n\n') # 逐个存入本地txt中,按自己所需要的格式做调整
f.write(test.replace(" ", "").replace("<br>", "").replace("\n\n", "\n").replace("\t", ""))
f.write("\n\n")
print(list.index(web))
f.close()
a.quit()
以上只是一些简单的用法,根据实际情况使用selenium的函数并封装好,有一定的可扩展性,还有其他的一些方法没有使用上。也可使用selenium做ui自动化测试,需要校验数据库等需要用到pymysql或其他方法。
有人问我为什么不直接使用request包,get/post直接获取页面,效率更高,而selenium包在等待页面时,会消耗很大一部分时间,毕竟中间通过了驱动。关于这个问题,可以自己去试试,就拿刚才我看小说的那个页面来说,request得到的html不会出现任何小说的文本内容,其他页面也一样,用request get下来的内容或多或少会隐藏一部分内容。
在复杂需求下,需要爬去该网站下每个链接的所有有用信息,而页面链接通常不会是有一定规律的,除了大量分析每个页面元素,该如何使用爬虫呢?比方说把豆瓣的所有影视资料都爬下来,该如何写呢?可细细思考。