自己想看一本网络小说但是网络上没有可以直接下载的txt格式文件到我的kindle上,于是想写个爬虫。使用python-selenium工具。

0、前提:已经安装好了python环境,包括环境变量。

1、下载selenium包。

      打开命令窗口,输入pip install selenium,即可安装好selenium包

python-selenium的使用——爬虫

2、下载浏览器驱动。

      下载地址:http://chromedriver.storage.googleapis.com/index.html

      根据自己浏览器对应的版本下载对应的驱动,例如我的浏览器版本是80.0.3**。引擎放在自己的爬虫文件的同一目录下即可。

python-selenium的使用——爬虫

 

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("&nbsp;", "").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下来的内容或多或少会隐藏一部分内容。

 

在复杂需求下,需要爬去该网站下每个链接的所有有用信息,而页面链接通常不会是有一定规律的,除了大量分析每个页面元素,该如何使用爬虫呢?比方说把豆瓣的所有影视资料都爬下来,该如何写呢?可细细思考。

 

 

 

 

 

 

 

相关文章: