目录
进入到项目中创建一个名为baidu的爬虫文件:后面必须指定一个网址,可以随便写后面可以改
然后到配置文件(settings.py)中进行修改: 这里没介绍的参数基本上都用处不大
当选择开启中间件的话,就需要在中间件文件(middlewares.py)中进行编辑了。
当选择开启管道时就得到管道文件中(pipelines.py)中编写存储操作了:
requests模块
安装:请进入到pycharm的设置中自行搜索 requests 进行安装
下面爬取一下百度的首页来介绍一些方法:
# -*- coding: UTF-8 -*- # 1. 导包 import requests # 2. 指定url url = "https://www.baidu.com" header = { # 设置请求头信息 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.63' } # 3. 使用GET方法发送请求,该方法会返回一个响应对象 response = requests.get(url=url,headers=header) # 4. 获取响应数据 # print(response.status_code) # 打印状态码 # print(response.url) # 打印请求的url # print(response.headers) # 打印响应头头信息 # print(response.text) # 以文本形式打印网页源码 # print(response.content) # 返回的是二进制类型的原生字符串形式的响应数据的 response.encoding = 'utf-8' # 指定编码格式,不然打开乱码
requests请求方法:
requests有很多个请求方法,最常用的为 post 和 get 方法:
res = requests.get() res = requests.post() res = requests.put() res = requests.delete() res = requests.head() res = requests.options()
requests请求方法内参数的介绍:
requests.方法( url=请求的网址, params=本次请求携带的 GET 参数, data=本次请求携带的 POST 参数, headers=本次请求携带的请求头信息, cookies=本次请求携带的cookie信息, files=本次请求要携带提交的文件, auth=身份验证, timeout=设置本次请求最长的请求时间-超时就会报错, allow_redirects=访问该网址时是否允许被重定向处理- True | False, proxies=代理, hooks=事件挂钩, stream=流式请求,主要对接流式 API, verify=是否进行证书验证 - True | False, cert=证书, json=本次请求携带的JSON格式的信息, )
建立会话对象
# s = requests.Session() # 后续都使用会话对象进行进行,而不是直接使用 requests 对象 s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') r = s.get("http://httpbin.org/cookies") print(r.text)
lxml 模块介绍:
lxml 是爬虫中最好用的一个模块了,它里面的方法可以将响应数据进行解析,从而检索获取到自己最想要的内容。使用前需安装 lxml 模块。
下面介绍一下 lxml 中常用的方法:使用前先导入模块:
from lxml.html import etree
etree.HTML() 方法
将传入的字符串格式的html源码转化成_Element对象。作为_Element对象,可以方便的使用xpath()等方法。
from lxml.html import etree html = ''' <html> <head> <title>XPath 语法</title> </head> <body> <div class="tag"> <div class="row"> <h1>row下的h1</h1> <div> <div class="logo"> <h1><a href="/1"</a>45</h1> <h1><a href="/2"</a>11</h1> <h1><a href="/3"</a></h1> </div> </div> </div> </div> <div class="tag"> <price>50</price> <price>20</price> </div> </body> </html> ''' response = etree.HTML(html) # 将html字符串源码转化成 Element对象 result = response.xpath(r"//div[@class='tag']") ''' 获取根下 class属性为 tag 的 全部 的div标签,返回的是列表里面存放这符合要求的全部的标签 (不管标签放在哪,只要符合 div[@class='tag'] 匹配规则就全部获取) 结果:[<Element div at 0x1d634ac4200>, <Element div at 0x1d634ac4500>] ''' result2 = response.xpath(r"//div[@class='tag']/div[1]/div[1]/div[1]/h1[last()-1]/a/@href") '''获取div为tag的标签下,第一个div下,的第一个div下, 的第一个div内的倒数第二[last()-1]个h1标签下的a标签内href属性的值 结果:['/2'] ''' result3 = response.xpath(r"//div[@class='logo']/../../h1/text()") ''' 获取div标签class属性为logo的父标签的父标签下的h1标签内的文本内容 结果:['row下的h1'] ''' result4 = response.xpath(r"//div[@class='logo']//h1") ''' 获取div标签class属性为logo下所有的h1标签 结果:[<Element h1 at 0x28406dd4840>, <Element h1 at 0x28406dd4cc0>, <Element h1 at 0x28406e80f00>] ''' result5 = response.xpath(r"//div[@class='logo']//h1[position()<3]") ''' 获取div标签class属性为logo下所有h1标签的前两个和h1标签,顾前不顾尾 结果:[<Element h1 at 0x14da59c4f00>, <Element h1 at 0x14da4f5ab80>] ''' result6 = response.xpath(r"//div[@class]") ''' 获取所有拥有class属性的div标签 结果:[<Element div at 0x15898e54cc0>, <Element div at 0x15898efd780>, <Element div at 0x15898efdf00>, <Element div at 0x15898e54fc0>] ''' result7 = response.xpath(r"//div[price>30]") '''获取div标签内price标签大于30的标签 结果:[<Element div at 0x1ebb8bc57c0>] ''' result8 = response.xpath(r"//*") '''获取所有标签属性的值 结果:['tag', 'row', 'logo', '/1', '/2', '/3', 'tag'] ''' result9 = response.xpath(r"//div[@class='logo']//*") '''获取div标签属性为logo下所有的标签 结果:[<Element h1 at 0x1d442ec1140>, <Element a at 0x1d...]一共获得六个标签 ''' print(result8)
etree.tostrint()方法
etree.tostrint()方法用来将_Element对象转换成字符串。
from lxml.html import etree html = '<html><body><h1>This <a>is a </a>test</h1></body></html>' _element = etree.HTML(html) # 将html字符串源码转化成 Element对象 print(type(_element)) # <class 'lxml.etree._Element'> h = _element.xpath('//h1') # 解析h1标签,返回的是拥有h1标签的列表 print(h) # [<Element h1 at 0x21a88ff7f80>] result = etree.tostring(h[0],encoding="utf-8",method='text') # 将列表中的h1标签转化成字符串格式,返回的是bytes类型的,需要对其进行解码 print(result.decode())
selenium浏览器自动化爬虫介绍:
selenium安装
打开cmd输入以下命令进行安装,或到pycharm设置内自行输入selenium进行安装
pip install -i https://pypi.douban.com/simple selenium
执行后,使用 pip show selenium 查看是否安装成功。
安装浏览器驱动
针对不同的浏览器,需要安装不同的驱动。下面列举了常见的浏览器与对应的驱动程序下载链接。
Firefox 浏览器驱动:Firefox
Chrome 浏览器驱动:Chrome
IE 浏览器驱动:IE
Edge 浏览器驱动:Edge
PhantomJS 浏览器驱动:PhantomJS
Opera 浏览器驱动:Opera
这里以安装 Chrome 驱动作为演示。但 Chrome 在用 selenium 进行自动化测试时还是有部分 bug ,常规使用没什么问题,但如果出现一些很少见的报错,可以使用 Firefox 进行尝试,毕竟是 selenium 官方推荐使用的。确定浏览器版本
在新标签页输入 chrome://settings/ 进入设置界面,然后选择 【关于 Chrome】
查看自己的版本信息。这里我的版本是104,这样在下载对应版本的 Chrome 驱动即可。
下载驱动打开 Chrome驱动 。单击对应的版本。
根据自己的操作系统,选择下载。
下载完成后,压缩包内只有一个 exe 文件。
将 chromedriver.exe 保存到任意位置,并把当前路径保存到环境变量中(我的电脑>>右键属性>>高级系统设置>>高级>>环境变量>>用户的变量或系统变量>>Path),添加的时候要注意不要把 path 变量给覆盖了,如果覆盖了千万别关机,然后百度。只需要添加到其所在的目录位置下如:
添加成功重启软件代码进行测试。
from selenium import webdriver # Chrome浏览器 driver = webdriver.Chrome()
有跳出 chrome浏览器 则代表成功。
浏览器控制相关:
窗口相关:
from selenium import webdriver # 不自动关闭浏览器 chrome_options = Options() chrome_options.add_argument('--headless') # 注意此处添加了options参数 driver = webdriver.Chrome(options=chrome_options) driver.get('https://www.csdn.net/') ----------------------------------------------- # 设置浏览器浏览器的宽高为:600x800 driver.set_window_size(600, 800) driver.maximize_window() # 最大化窗口 driver.minimize_window() # 最小化窗口 driver.fullscreen_window() # 全屏 print(driver.get_window_position()) # 获取窗口位置 print(driver.get_window_size()) # 获取窗口大小 print(driver.get_window_rect()) # 同时获取窗口位置和大小 driver.set_window_position(30,30) # 设置窗口位置 driver.set_window_size(500,500) # 设置窗口大小 driver.set_window_rect(10,10,1050,708) # 同时设置窗口位置和大小
浏览器前进和后退:以及跳转新标签页面
# decoding:utf-8 from selenium import webdriver from time import sleep driver = webdriver.Chrome() # 访问CSDN首页 driver.get('https://www.csdn.net/') sleep(2) #访问CSDN个人主页---在原页面打开 driver.get('https://blog.csdn.net/adjnd?spm=1000.2115.3001.5343') sleep(2) # # 访问CSDN个人主页---新标签中打开 # js = "window.open('https://blog.csdn.net/adjnd?spm=1000.2115.3001.5343')" # driver.execute_script(js) # sleep(2) #返回(后退)到CSDN首页 driver.back() sleep(2) #前进到个人主页 driver.forward()
浏览器刷新
在一些特殊情况下我们可能需要刷新页面来获取最新的页面数据,这时我们可以使用
refresh()
来刷新当前页面。# 刷新页面 driver.refresh()
浏览器窗口切换
在很多时候我们都需要用到窗口切换,比如:当我们点击注册按钮时,它一般会打开一个新的标签页,但实际上代码并没有切换到最新页面中,这时你如果要定位注册页面的标签就会发现定位不到,这时就需要将实际窗口切换到最新打开的那个窗口。我们先获取当前各个窗口的句柄,这些信息的保存顺序是按照时间来的,最新打开的窗口放在数组的末尾,这时我们就可以定位到最新打开的那个窗口了。
# 获取打开的多个窗口句柄 windows = driver.window_handles # 切换到当前最新打开的窗口---可按照获取指定页面的句柄进行跳转到指定页面中 driver.switch_to.window(windows[-1])
那如果打开的窗口有多个,如何跳转到指定的窗口?如果确实有这个需求,那么打开窗口时就需要记录每一个窗口的
key
(别名) 与value
(handle
),保存到字典中,后续根据key
来取handle
。表单切换
很多页面也会用带 frame/iframe 表单嵌套,对于这种内嵌的页面 selenium 是无法直接定位的,需要使用 switch_to.frame() 方法将当前操作的对象切换成 frame/iframe 内嵌的页面。
switch_to.frame() 默认可以用的 id 或 name 属性直接定位,但如果 iframe 没有 id 或 name ,这时就需要使用 xpath 进行定位。下面先写一个包含 iframe 的页面做测试用。
<!DOCTYPE html> <html lang="en"> <head> </head> <body> <!-- <iframe src="https://blog.csdn.net/adjnd" width="400" height="200"></iframe>--> <iframe id="CSDN_info" name="cc" src="https://blog.csdn.net/adjnd" width="400" height="200"></iframe> </body> </html>
然后进行框架(iframe/frame)切换:
# decoding:utf-8 from selenium import webdriver from selenium.webdriver.common.by import By from pathlib import Path driver = webdriver.Chrome() # 读取本地html文件 driver.get('file:///' + str(Path(Path.cwd(), 'iframe测试.html'))) # 1.通过id定位 # driver.switch_to.frame('CSDN_info') # 2.通过name定位 driver.switch_to.frame('cc') # 3.通过xpath定位 # iframe_label = driver.find_element(By.XPATH,'/html/body/iframe') # driver.switch_to.frame(iframe_label) driver.find_element(By.XPATH,'//*[@id="csdn-toolbar"]/div/div/div[1]/ul/li[1]/a').click()
其他浏览器中常见的操作:
webdriver中的常见操作有:
以 CSDN 首页为例,需要用到的就是搜素框和搜索按钮。通过下面的例子就可以了解各个操作的用法了。
# decoding:utf-8 from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('https://www.csdn.net/') sleep(2) # 定位搜索输入框 text_label = driver.find_element(By.XPATH,'//*[@id="toolbar-search-input"]') # 在搜索框中输入 苹果 text_label.send_keys('苹果') sleep(2) # 清除搜索框中的内容 text_label.clear() # 输出搜索框元素是否可见,可见为true print(text_label.is_displayed()) # 判断该元素是否可见 # 输出搜索框内占位符的值 print(text_label.get_attribute('placeholder')) # 获取标签属性值 # 定位搜索按钮 button = driver.find_element(By.XPATH,'//*[@id="toolbar-search-button"]/span') # 输出按钮的大小 print(button.size) # 返回元素的尺寸 # 输出按钮上的文本 print(button.text) # 返回元素的文本
![]()
页面元素定位介绍
定位单个元素:
# decoding:utf-8 from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('https://www.csdn.net/') sleep(2) ''' 注意,只需在解析的结果后调用 .text 就可以获得解析的标签内的文本了 ''' driver.find_element(By.ID, "toolbarBox") ''' 标签的 id 具有唯一性,就像人的身份证,由于 id 的唯一性, 我们可以通过 id 定位到它,我们可以不用管其他的标签的内容。''' driver.find_element(By.NAME, "keywords") ''' 获取name为指定值的全部标签''' driver.find_element(By.CLASS_NAME, "tag") ''' 获取class为指定值的全部标签 ''' driver.find_element(By.TAG_NAME, "div") ''' 获取页面中全部的指定的tag标签''' driver.find_element(By.LINK_TEXT, "下载·课程") ''' 只能用于<a>标签 -- 用于一些<a>标签名字比较短的。通过指定文本获取该标签''' driver.find_element(By.PARTIAL_LINK_TEXT, "下载·") ''' 只能用于<a>标签 -- 用于一些<a>标签名字很长,我们可以选取一部分特殊的词去定位。''' driver.find_element(By.XPATH, '//*[@id="floor-nav_557" and @floor-index="0"]') ''' 通过 xpath 解析指定规则的标签,xpath规则可自己在文中查看 获取id为 floor-nav_557 和 floor-index=“0” 的标签'''
css定位。使用选择器来为页面元素绑定属性,它可以较为灵活的选择控件的任意属性,
CSS
选择器常见语法:driver.find_element(By.CSS_SELECTOR, '[value="1"]')
方法 例子 描述 .class .toolbar-search-container
选择 class = 'toolbar-search-container'
的所有元素#id #toolbar-search-input
选择 id = 'toolbar-search-input'
的元素* *
选择所有元素 element input
选择所有 <input\>
元素element>element div>input
选择父元素为 <div\>
的所有<input\>
元素element+element div+input
选择同一级中在 <div\>
之后的所有<input\>
元素[attribute=value] type='text'
选择 type = 'text'
的所有元素定位多个元素:
上篇讲述了定位一个元素的 8 种方法,定位一组元素使用的方法只需要将
element
改为elements
即可,它的使用场景一般是为了批量操作元素。如:获取多个指定的标签from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('https://www.csdn.net/') p_list = driver.find_elements(By.XPATH,'//*[@id="floor-nav_557"]/div/div/div/ul/li//a') name = [p.text for p in p_list] # 循环解析获取文本 print(name) # 结果:['后端', '前端', '移动开发', '编程语言', 'Java']
鼠标控制
在webdriver 中,鼠标操作都封装在ActionChains类中,常见方法如下:
方法 描述 click()
单击左键 context_click()
单击右键 double_click()
双击 drag_and_drop()
拖动 move_to_element()
鼠标悬停 perform()
执行所有ActionChains中存储的动作 # decoding:utf-8 from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome() driver.get('https://www.csdn.net/') sleep(2) # 定位搜索按钮 button = driver.find_element(By.XPATH, "//*[@id='toolbar-search-button']/span") button.click() ''' 执行单击操作 -- 左键不需要用到 ActionChains ''' ActionChains(driver).context_click(button).perform() ''' 执行右击操作 -- 右键搜索按钮''' ActionChains(driver).double_click(button).perform() ''' 执行双击动作''' source = driver.find_element(By.XPATH, '//*[@id="floor-www-index_558"]/div/div[2]') target = driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]') ActionChains(driver).drag_and_drop(source, target).perform() # 执行拖动操作 ''' 模拟鼠标拖动操作,该操作有两个必要参数, source:鼠标要拖动的元素 target:鼠标拖至并释放的目标元素 ''' # 定位指定元素 collect = driver.find_element(By.XPATH, '//*[@id="csdn-toolbar"]/div/div/div[1]/ul/li[9]/a') ''' 悬停至定位的元素处 ''' ActionChains(driver).move_to_element(collect).perform()
键盘控制
webdriver中Keys类几乎提供了键盘上的所有按键方法,我们可以使用send_keys + Keys实现输出键盘上的组合按键如“Ctrl + C”、“Ctrl + V”等。
# decoding:utf-8 from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get('https://www.csdn.net/') sleep(2) # 定位输入框并输入文本 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys('python') # (输入内容后)模拟回车键进行跳转 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys(Keys.ENTER) sleep(2) # 跳回原本页面 windows = driver.window_handles driver.switch_to.window(windows[0]) sleep(2) # 使用 Backspace 来删除一个字符 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys(Keys.BACK_SPACE) sleep(2) # Ctrl + A 全选输入框中内容 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys(Keys.CONTROL, 'a') # Ctrl + x 剪切输入框内容 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys(Keys.CONTROL, 'x') sleep(2) # Ctrl + V 粘贴输入框中内容 driver.find_element(By.XPATH, '//*[@id="toolbar-search-input"]').send_keys(Keys.CONTROL, 'v')
其他常见键盘操作:
操作 描述 Keys.F1
F1键 Keys.SPACE
空格 Keys.TAB
Tab键 Keys.ESCAPE
ESC键 Keys.ALT
Alt键 Keys.SHIFT
Shift键 Keys.ARROW_DOWN
向下箭头 Keys.ARROW_LEFT
向左箭头 Keys.ARROW_RIGHT
向右箭头 Keys.ARROW_UP
向上箭头
设置元素等待(处理动态页面)
很多页面都使用 ajax(动态加载) 技术,页面的元素不是同时被加载出来的,为了防止定位这些尚在加载的元素时,报错,可以设置元素等来增加脚本的稳定性。webdriver 中的等待分为 显式等待 和 隐式等待。
显式等待
显式等待:设置一个超时时间,每个一段时间就去检测一次该元素是否存在,如果存在则执行后续内容,如果超过最大时间(超时时间)则抛出超时异常(TimeoutException)。显示等待需要使用 WebDriverWait,同时配合 until 或 not until 。下面详细讲解一下。
method 中的预期条件判断方法是由 expected_conditions 提供,下面列举常用方法。
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait # 导入显示等待模块 from selenium.webdriver.support import expected_conditions as EX # 导入元素判断模块,用于判断一些条件 from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://www.csdn.net/") locator = (By.ID, 'app') # locator_2 = (By., 'app') element_object = driver.find_element(By.ID, 'app') element = WebDriverWait(driver, # 浏览器驱动 timeout=5, # 设置超时时间,单位秒 poll_frequency=0.5, # 每次检测的间隔时间,默认为0.5秒 ignored_exceptions=None # 指定要忽略的异常信息,如果在调用 until 或 until_not 的过程中抛出指定要忽略的异常信息的话,则中断代码,抛出异常,默认忽略的只有 NoSuchElementException 。 ).until( # 指定判断方法 # method=EX.title_contains('开发者'), # 判断当前页面的 title 标签中是否包含预期字符串 - 包含为 True,不包含的话就报错 # method=EX.text_to_be_present_in_element(locator, '开发者'), # 判断元素中的 文本 是否包含了预期的字符串 - 包含为 True,不包含的话就报错,传入的是元组形式的定位器 # method=EX.title_is('开发者'), # 判断当前页面的 title 标签中是否等于预期字符串 - 等于为 True,不等于的话就报错 # method=EX.presence_of_element_located(locator), # 判断元素是否被加到了 dom树 (网页源码) 里,并不代表该元素一定可见,传入的是元组形式的定位器,源码内没有该元素的话就报错 # method=EX.visibility_of_element_located(locator), # 判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0,传入的是元组形式的定位器,源码内没有该元素的话就报错 # method=EX.text_to_be_present_in_element_value(locator, '--'), # 判断元素中的 value 属性是否包含了预期的字符串,传入的是元组形式的定位器,不包含的话就报错, # method=EX.frame_to_be_available_and_switch_to_it(locator), # 判断元素中的 value 属性是否包含了预期的字符串,传入的是元组形式的定位器,不包含的话就报错, # method=EX.invisibility_of_element_located(locator), # 判断该元素是否不存在于 dom 树或不可见,传入的是元组形式的定位器, # method=EX.element_to_be_clickable(locator), # 判断元素是否可见并且是可点击的,传入的是元组形式的定位器, # method=EX.staleness_of(element_object), # 等待元素从 dom 树中移除 # method=EX.element_to_be_selected(element_object), # 判断元素是否被选中,一般用在下拉列表,传入的是 element_object 的定位器,不是的话就报错, # method=EX.element_selection_state_to_be(element_object, True), # 判断元素的选中状态是否符合预期,传入的是 element_object 的定位器,第二个参数为 True/False # method=EX.element_located_selection_state_to_be(locator, True), # 判断元素的选中状态是否符合预期,传入的是元组形式的定位器,不包含的话就报错, # method=EX.alert_is_present(), # 判断页面上是否存在 alert,不存在的话就报错, message='qw') # 如果超时或报错的话,抛出 TimeoutException 异常,并显示 message 中的内容 print(element)
隐式等待
隐式等待是全局性的,即运行过程中,如果元素可以定位到,它不会影响代码运行,但如果定位不到,则它会以轮询的方式不断地访问元素直到元素被找到,若超过指定时间,则抛出异常。
使用
implicitly_wait()
来实现隐式等待,使用难度相对于显式等待要简单很多。
示例:打开个人主页,设置一个隐式等待时间 5s,通过id
定位一个不存在的元素,最后打印 抛出的异常 与 运行时间。from selenium import webdriver from time import time from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('https://www.csdn.net/') start = time() driver.implicitly_wait(5) try: driver.find_element(By.ID,'kw') except Exception as e: print(e) print(f'耗时:{time() - start}')
强制等待
使用
time.sleep()
强制等待,设置固定的休眠时间,对于代码的运行效率会有影响。以上面的例子作为参照,将 隐式等待 改为 强制等待。from selenium import webdriver from time import time, sleep from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get('https://www.csdn.net/') start = time() sleep(5) try: driver.find_element(By.ID,'kw') except Exception as e: print(e) print(f'耗时:{time() - start}')
值得一提的是,对于定位不到元素的时候,从耗时方面隐式等待和强制等待没什么区别。但如果元素经过 2s 后被加载出来,这时隐式等待就会继续执行下面的代码,但 sleep还要继续等待 3s。
弹窗处理:
JavaScript
有三种形式的弹窗框 1、alert
(确认) 2、confirm
(确认、取消)3 、
prompt
(文本框、确认、取消)。先编写一个演示的 HTML 文件:<!DOCTYPE html> <html lang="en"> <head> </head> <body> <button id="alert">alert</button> <button id="confirm">confirm</button> <button id="prompt">prompt</button> <script type="text/javascript"> const dom1 = document.getElementById("alert") dom1.addEventListener('click', function(){ alert("alert hello") }) const dom2 = document.getElementById("confirm") dom2.addEventListener('click', function(){ confirm("confirm hello") }) const dom3 = document.getElementById("prompt") dom3.addEventListener('click', function(){ prompt("prompt hello") }) </script> </body> </html>
处理方式:先使用(
switch_to.alert
自动获取当前弹窗),再使用
text() : 获取弹窗文本信息
、
accept() : 点击弹窗中的确定按钮
、
dismiss() : 点击弹窗中的取消按钮
、
send_keys("**") : 将指定的文本内容写入到弹窗中的文本框中
等方法进行操作,如:
# decoding:utf-8 from selenium import webdriver from selenium.webdriver.common.by import By from pathlib import Path from time import sleep driver = webdriver.Firefox() # 由于selenium不能和chrome完全兼容,导致不能往文本框内输入文本,所以本次使用火狐进行操作 driver.get('file:///' + str(Path(Path.cwd(), '测试.html'))) sleep(2) driver.find_element(By.XPATH,'//*[@id="alert"]').click() # 点击alert按钮 sleep(1) alert = driver.switch_to.alert # 获取alert弹窗对象 print(alert.text) # 打印文本--- 结果:alert hello alert.accept() # 点击确认 sleep(2) driver.find_element(By.XPATH,'//*[@id="confirm"]').click() # 点击confirm按钮 sleep(1) confirm = driver.switch_to.alert # 获取confirm弹窗对象 print(confirm.text) # 打印文本--- 结果:confirm hello confirm.dismiss() # 点击取消 sleep(2) driver.find_element(By.XPATH,'//*[@id="prompt"]').click() # 点击confirm按钮 sleep(1) prompt = driver.switch_to.alert # 获取prompt弹窗对象 print(prompt.text) # 打印文本--- 结果:prompt hello prompt.send_keys("---") # 向prompt的输入框中传入文本 sleep(2) prompt.accept() # 点击确认
上传 & 下载文件
上传文件
常见的 web 页面的上传,一般使用
input
标签或是插件(JavaScript
、Ajax
),对于input
标签的上传,可以直接使用send_keys(路径)
来进行上传。
先写一个测试用的页面。<!DOCTYPE html> <html lang="en"> <head> </head> <body> <input type="file" name="upload"> </body> </html>
下面通过
xpath
定位input
标签,然后使用send_keys(str(file_path)
上传文件。# decoding:utf-8 from selenium import webdriver from selenium.webdriver.common.by import By from pathlib import Path driver = webdriver.Chrome() file_path = Path(Path.cwd(), '上传下载.html') # 获取到要解析的文件路径 driver.get('file:///' + str(file_path)) # 访问该文件 # 将该文件上传(发送)到网页中 driver.find_element(By.XPATH,'//*[@name="upload"]').send_keys(str(file_path))
下载文件:
chrome浏览器
# decoding:utf-8 from selenium import webdriver from selenium.webdriver.common.by import By from pathlib import Path prefs = {'profile.default_content_settings.popups': 0, # 为0 则禁止弹出窗口。 'download.default_directory': str(Path.cwd())} # 设置下载路径。为当前路径 option = webdriver.ChromeOptions() option.add_experimental_option('prefs', prefs) # 添加设置 driver = webdriver.Chrome(options=option) # 将设置传入驱动中 # 访问图片页面,定位到下载按钮并点击下载按钮 driver.get("https://pic.sogou.com/d?query=%E7%83%9F%E8%8A%B1&did=4&category_from=copyright") driver.find_element(By.XPATH,'//*[@id="foot"]/div[1]/div[2]/a').click() driver.switch_to.window(driver.window_handles[-1]) driver.find_element(By.XPATH,'./html').send_keys('thisisunsafe') ''' 点击下载时页面弹出不是私密连接,则需要切换到该页面并发送 thisisunsafe 这段话 告诉浏览器本次请求连接是安全的 '''
运行之后就可以看到当前目录下多了一张图片了。
Firefox浏览器:
- HTTP Content-type对照表:HTTP content-type
# decoding:utf-8 from selenium import webdriver from selenium.webdriver.common.by import By import os fp = webdriver.FirefoxProfile() fp.set_preference("browser.download.dir", os.getcwd()) # 指定下载目录位置 fp.set_preference("browser.download.folderList", 2) # 0 代表按浏览器默认下载路径;2 代表保存到指定的目录。 fp.set_preference("browser.download.manager.showhenStarting", True) # 是否显示开始,boolean 类型。 fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream") # 对指定文件类型不再弹出框进行询问。 driver = webdriver.Firefox(firefox_profile=fp) # 将设置传入到驱动器中 # 访问页面,点击下载图片 driver.get("https://pic.sogou.com/d?query=%E7%83%9F%E8%8A%B1&did=4&category_from=copyright") driver.find_element(By.XPATH, '//*[@id="foot"]/div[1]/div[2]/a').click()
运行之后就可以看到当前目录下多了一张图片了。
cookies操作
cookies 是识别用户登录与否的关键,爬虫中常常使用 selenium + requests 实现 cookie持久化,即先用 selenium 模拟登陆获取 cookie ,再通过 requests 携带 cookie 进行请求。
webdriver 提供 cookies 的几种操作:读取、添加删除。
- get_cookies:以字典的形式返回当前会话中可见的 cookie 信息。
- get_cookie(name):返回 cookie 字典中 key == name 的 cookie 信息。
- add_cookie(cookie_dict):将 cookie 添加到当前会话中
- delete_cookie(name):删除指定名称的单个 cookie。
- delete_all_cookies():删除会话范围内的所有 cookie。
下面看一下简单的示例,演示了它们的用法。
# decoding:utf-8 from selenium import webdriver driver = webdriver.Chrome() driver.get("https://blog.csdn.net/") # 输出所有cookie信息 print(driver.get_cookies()) cookie_dict = { 'domain': '.csdn.net', 'expiry': 1664765502, 'httpOnly': False, 'name': 'test', 'path': '/', 'secure': True, 'value': 'null'} driver.add_cookie(cookie_dict) # 添加cookie print(driver.get_cookie('test')) # 显示 name = 'test' 的cookie信息 driver.delete_cookie('test') # 删除 name = 'test' 的cookie信息 driver.delete_all_cookies() # 删除当前会话中的所有cookie
滑动滚动条:
webdriver
对于滚动条的处理需要用到JavaScript
,同时也可以向textarea
文本框中输入文本(webdriver
只能定位,不能输入文本),webdriver
中使用 execute_script 方法实现JavaScript
的执行。通过 x , y 坐标滑动滚动条:
对于这种通过坐标滑动的方法,我们需要知道做表的起始位置在页面左上角(0,0),下面看一下示例,滑动 CSDN 首页。
# decoding:utf-8 from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get("https://blog.csdn.net/") sleep(1) js = "window.scrollTo(0,500);" # 设置要滑动到的目标位置 driver.execute_script(js) # 进行滑动
通过参照标签滑动:
from selenium import webdriver from time import sleep from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://blog.csdn.net/") sleep(1) # 将滑块滑动到定位器定位到的元素的那个位置 target = driver.find_element(By.XPATH,'//*[@id="floor-blog-index_747"]/div/div[1]/div[1]/div') driver.execute_script("arguments[0].scrollIntoView();", target)
其他操作:
关闭所有页面
driver.quit() # 关闭所有窗口并退出驱动程序。
关闭当前页面:
driver.close() ''' 注意,该语句只能关闭当前句柄窗口定位的页面,要关闭指定页面需要切换到指定窗口中才行 '''
对当前页面进行截图操作:
对页面截图这一功能,主要用在我们测试时记录报错页面的,我们可以将
try except
结合get_screenshot_as_file()
一起使用来实现这一效果。try: # 对可能会发生错误的按钮进行点击操作 driver.find_element(By.XPATH,'//*[@id="mainContent"]/aside/div[1]/div').click() except: # 当发生错误时截图错误信息,并保存到指定位置内 driver.get_screenshot_as_file(r'C:\Users\pc\Desktop\screenshot.png')
常用方法:
driver.current_url # 获取当前页面url driver.page_source # 获取当前html源码 driver.title # 获取当前页面标题 driver.name # 获取浏览器名称(chrome) driver.get_screenshot_as_png() # 对页面进行截图,返回二进制数据 driver.get_window_size() # 设置浏览器尺寸 driver.get_window_rect() # 获取浏览器尺寸,位置 driver.get_window_position() # 获取浏览器位置(左上角) driver.set_window_size(width=1000, height=600) # 设置浏览器尺寸 driver.set_window_position(x=500, y=600) # 设置浏览器位置(左上角) driver.set_window_rect(x=200, y=400, width=1000, height=600) # 设置浏览器的尺寸,位置
selenium隐藏指纹特征
简单来说就是让selenium自动化爬虫看起来更像人一点,减少被网站检查到是机器人的可能性,该步操作只需下载一个 node.js 即可,如果已安装的读者可以直接运行如下命令即可在当前目录生成一个
stealth.min.js
文件。npx extract-stealth-evasions
然后就可以用这个文件进行隐藏操作了。如:
import time from selenium.webdriver import Chrome option = webdriver.ChromeOptions() option.add_argument("--headless") # 无头浏览器需要添加user-agent来隐藏特征 option.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36') driver = Chrome(options=option) driver.implicitly_wait(5) with open('stealth.min.js') as f: js = f.read() driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": js }) driver.get('https://bot.sannysoft.com/') driver.save_screenshot('hidden_features.png')
这样就好了。详细操作请见:里面的selenium隐藏指纹
Scrapy 框架详解:
Scrapy安装
- pip install wheel
- 下载twisted,下载地址为:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
- 安装twisted, pip install 下载的文件具体位置及名称
- pip install pywin32
- pip install scrapy
Scrapy框架图解:
Scrapy命令介绍:
- 创建一个工程的命令:cd进入到指定目录 > scrapy startproject project_name
- cd进入到project_name目录里面
- 在spiders目录里创建一个爬虫文件:> scrapy genspider reptile_name www.xxx.com
- 数据获取及解析
- 执行工程:在终端输入 > scrapy crawl reptile_name
- 持久化存储:
- 终端命令存储:
- 限制:只可以将return item 进行存储到本地文本文件中,只能存储一次,存完之后就会停止那一次函数了
- 注意:终端持久化存储的后缀只可以是('json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')
- 指令:scrapy crawl spider_name -o path_name.后缀
- 好处:简介高效便捷
- 坏处:局限性高
- 管道存储:
- 编码流程:
- 数据解析
- 在item类中定义相关属性
- 将解析到的数据封装存储到item类型的对象中
- 将item类型的对象提交给管道进行持久化存储
- 在管道类的process_item中要将其接收到的item对象中数据进行持久化存储
- 在配置文件中开启管道
- 好处:
- 通用性强
流程介绍:
- 先在自定的目录内调用终端窗口创建一个项目:
- 然后进入到该项目中,创建一个爬虫文件
- 然后在爬虫文件内编辑自己想要的内容
- 在配置文件中进行自定的配置
- 当选择开启管道时:
- 在 items.py 文件中创建自己想要的参数信息
- 然后在爬虫文件中导入items.py中的内容,进行数据的存储,然后将数据传送到管道
- 在管道文件中编辑自己想要的内容
- 当选择开启中间件时:
- 到中间件中编辑自己想要的内容
- 当选择终端存储时,直接到项目的终端目录中输入 scrapy crawl spider_name -o path_name.后缀 即可将 return item 内的值进行存储操作
实战讲解:
创建一个名为test_的项目:
进入到项目中创建一个名为baidu的爬虫文件:后面必须指定一个网址,可以随便写后面可以改
目录介绍:
![](https://img-blog.csdnimg.cn/557938071b1f4c26ac7b03e4023409ce.jpeg)
先到爬虫文件(baidu.py)中进行编辑:
# decoding:utf-8
import scrapy
from ..items import TestItem # 导入文件下的item
class BaiduSpider(scrapy.Spider):
name = 'baidu' # 爬虫文件的名称
# allowed_domains = ['www.xxx.com'] # 限制可访问的url列表 无用
start_urls = ['https://www.baidu.com/'] # 起始访问的url列表
# 爬虫文件会先将响应数据发到 parse 方法中,再由该方法自行处理
def parse(self, response):
# 解析拿到页面中的图片标签内的url,返回的是列表,列表内放着获取到的对象信息
url_list = response.xpath('//*[@id="s-top-left"]/a[6]/@href')
# 结果:[<Selector xpath='//*[@id="s-top-left"]/a[6]/@href' data='http://image.baidu.com/'>]
url = url_list.extract_first() # 拿到列表中的第一个元素,并将其转为字符串,也就是url本尊
# 结果:http://image.baidu.com/
# url = url_list.extract() # 这个方法则是将列表中所有的对象元素都转为字符串,返回的是list类型的
# 结果:[ 'http://image.baidu.com/','http://map.baidu.com',]
item = TestItem() # 将用来传递值的函数进行实例化处理
item['name_1'] = 'parse内赋的值' # 将值赋给item中的 name_1 参数
# yield item # 将存好值后的item传给管道进行存储处理
'''调用 yield 把控制权给管道,管道拿到 item 后进行处理,处理结束后再回到该程序继续执行后续流程。'''
'''
yield 与 return 的异同:
共同点:return 和 yield 都用来返回值;在一次性地返回所有值场景中return和yield的作用是一样的。
不同点:如果要返回的数据是通过循环生成的则。return 只能在循环外部一次性地返回,
yield 则可以在循环内部逐个元素返回。return 会在返回结果后结束函数的运行,
而使用yield时,每执行一次yield语句,函数就会被冻结,先把yield语句处理好,然后等函数被唤醒后再去执行后续代码。
'''
""" 这个yield的意思是先将函数冻结,然后对url进行请求,将响应数据和meta内的东西传给指定的函数进行处理,
等那个函数处理好后,会自行告诉这个函数内的yield,然后yield继续执行这个函数,直到这个函数处理结束"""
yield scrapy.Request(url=url, # 请求的url
callback=self.parse_detail, # 请求后要将响应数据传给哪个函数处理
meta={'item': item}, # 将该函数内的东西传到上面指定的函数中
method='GET', # 指定本次请求的方法,默认为GET
)
def parse_detail(self, response):
# 以上面定义的键key名拿到传来的东西
item = response.meta['item']
imag_url_list = response.xpath('//*[@id="bd-home-content-album"]/a//@href').extract()
for i in imag_url_list:
item['name_2'] = i
yield item # 将存好值后的item传给管道进行存储处理
'''调用 yield 把控制权给管道,管道拿到 item 后进行处理,处理结束后再回到该程序继续执行后续流程。'''
然后到配置文件(settings.py)中进行修改: 这里没介绍的参数基本上都用处不大
# decoding:utf-8
BOT_NAME = 'test_' # 项目名
SPIDER_MODULES = ['test_.spiders']
NEWSPIDER_MODULE = 'test_.spiders'
LOG_LEVEL = 'ERROR'
# 设置能显示的日志信息,设置为只能显示错误的日志信息,不显示其他日志信息,这样执行程序时就会非常的直观简洁了
# 全局(整个项目共同使用)的 UA 伪装
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70'
# DEFAULT_REQUEST_HEADERS = { # 全局使用的请求头参数
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
# }
ROBOTSTXT_OBEY = False # 是否遵循君子协议,需要改为 False,不能爬不到多少东西
# CONCURRENT_REQUESTS = 32 # 同时允许开启多少个爬虫线程
# DOWNLOAD_DELAY = 3
''' 控制爬虫爬取的频率,根据你的项目调整,不要太快也不要太慢,默认是3秒,即爬一个停3秒,
设置为1秒性价比较高,如果要爬取的文件较多,写零点几秒也行'''
# COOKIES_ENABLED = False # 是否保存 COOKIES,默认关闭,开机可以记录爬取过程中的 COOKIE,非常好用的一个参数
""" 项目管道,用于存储数据的,取消注释即可开启,300为优先级,越低越爬取的优先度越高
pipelines.py 里的类必须在这个字段中使用全类名定义,这样才能开启 piplines.py 里的类,否则不能使用。"""
ITEM_PIPELINES = {
'test_.pipelines.TestPipeline': 300,
}
# SPIDER_MIDDLEWARES = { # 爬虫中间件,取消注释即可开启中间件
# 'test_.middlewares.TestSpiderMiddleware': 543, # 数据会先传给值低的中间件,由低到高传递数据
# }
# DOWNLOADER_MIDDLEWARES = { # 下载中间件,取消注释即可开启中间件
# 'test_.middlewares.TestDownloaderMiddleware': 543, # 数据会先传给值低的中间件,由低到高传递数据
# }
当选择开启中间件的话,就需要在中间件文件(middlewares.py)中进行编辑了。
要使用代理或者随机ua的话可以见:代理--ua 介绍
""" 这里没介绍的东西基本上用处都不大"""
from scrapy import signals
from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse # 从scrapy.http下导入处理响应数据的模块
# 由于爬虫中间件和下载中间件的作用和用法基本一样,所以通常只用下载中间件进行处理就好了
class TestDownloaderMiddleware:
def process_request(self, request, spider):
"""
该方法是拦截请求的。当请求经过下载中间件时可将其拦截,从而对这个请求进行处理。如修改请求参数等等。
该方法会因为返回的值而决定下步该做什么:
当返回的是 None 时,有两种情况:
- 第一是当在settings.py中注册了多个下载中间件类时,他会将继续调用下一个类中的 process_request 这个方法
- 第二是当只有这个下载中间件类时,他会将请求发送给下载器进行请求处理
当返回的是 response 对象时,不将请求传给下载器,而是直接传给引擎让引擎传给爬虫文件进行处理
当返回的是 request 对象时,会将请求发给引擎,让引擎发给调度器进行处理后继续进行请求处理
"""
return None
def process_response(self, request, response, spider):
"""
该方法是拦截响应的。当响应数据经过下载中间件时可将其拦截,从而对这个响应进行处理。
如:判断这个响应数据不是我们想要的响应数据,就可以在这里将该响应数据进行拦截,
然后在这里去再次请求获取到我们想要的响应数据,然后将两者进行替换后将我们想要的响应数据传给引擎
让其传给爬虫文件进行处理.
该方法可接受两个返回值,分别是:
当返回的是 response 对象时,有两个情况:
- 第一是当在settings.py中注册了多个下载中间件类时,他会继续调用下一个类中的 process_response 这个方法
- 第二是当只有这个下载中间件类时,直接传给引擎让引擎传给爬虫文件进行处理
当返回的是 request 对象时,会将请求发给引擎,让引擎发给调度器进行处理后继续进行请求处理
"""
# driver = spider.driver # 调用创建的爬虫程序里的driver参数
#
# if request.url in spider.title_url_list: # 当请求的网站在爬虫程序里保存的要拦截的网址list里面时执行数据修改
# driver.get(request.url) # 自动化对拦截到的请求发起selenium请求
# sleep(1)
# page_code = driver.page_source # 拿到自动化请求时的页面源码数据 拿到动态数据
# # 将旧的响应数据篡改成新的响应数据 然后附带对应要篡改的值
# new_response = HtmlResponse(url=request.url, body=page_code, encoding='utf-8', request=request)
# return new_response # 将篡改后的响应数据返回给爬虫程序进行对应操作
#
# else:
# return response # 当他不是我们要篡改的数据时直接放过他
pass
def process_exception(self, request, exception, spider):
# 拦截出现异常的数据 讲异常的数据进行修正 在返回进行请求发送 代理ip等等
""" 当在请求的过程中发生异常时,可以通过这个方法来拦截异常,并进行处理。这样就不会因为报错而使得程序停止了。
三种返回值的处理情况:
- None: 继续交给后续中间件处理异常
- Response对象: 将响应数据传给引擎让其传给爬虫文件
- Request对象: 将请求传给引擎让其传给调度器进行处理
"""
pass
接下来到items.py中定义想要的参数名:
# decoding:utf-8
import scrapy
class TestItem(scrapy.Item):
"""
在这里按照他给的格式定义自己想要的 key 名,
然后就可以通过这个key名在爬虫文件中传入自定的value值,
然后就可以在管道文件中获取到指定key名的value值了,
从而完成在管道中获取想要存储的数据内容
"""
# name = scrapy.Field()
name_1 = scrapy.Field()
name_2 = scrapy.Field()
pass
当选择开启管道时就得到管道文件中(pipelines.py)中编写存储操作了:
# decoding:utf-8
from itemadapter import ItemAdapter
class TestPipeline:
def open_spider(self,spider):
""" 该方法只执行一次。是在 爬虫文件 开启的时候被自动调用的。在这里我们可以做一些初始化操作,
如开启数据库连接等。其中,参数 spider 就是被开启的 爬虫文件 对象。
可以调用该对象内的方法,里面的方法就是爬虫文件中定义的方法"""
print("开始...")
self.fp = open('url.txt','w',encoding='utf-8')
def process_item(self, item, spider):
""" 当在爬虫文件中执行了 yield item 语句时,其就会将存放了数据的item传到该方法中
然后就可以在该方法中对数据进行存储操作了。参数 spider 就是被关闭的 爬虫文件 对象。"""
name_1 = item["name_1"] # 通过在items.py中定义的键名来获取其中的值
name_2 = item["name_2"]
self.fp.write(name_1+" : "+name_2+'\n')
return item # 函数的最后必须添加这句话,用处是将 item 返回出来,让后续的函数可以继续使用
def close_spider(self,spider):
""" 该方法只执行一次。是在 爬虫文件 关闭的时候自动调用的。在这里我们可以做一些收尾工作,
如关闭数据库连接等。其中,参数 spider 就是被关闭的 爬虫文件 对象。"""
self.fp.close()
print("结束...")
然后就可以到项目目录下执行以下语句进行开启项目了。
当选择的是终端存储的话就需要到爬虫文件中重新编辑了
注意,终端存储只能存储return item 的返回值
return item
""" 只需要将此行代码添加到爬虫文件中即可调用终端存储进行存储值了,
终端存储有一个弊端,就是只要程序一执行 return 的话该次函数就会停止了,
所以只能将值都存好了在将其返回才是有用的"""
然后在项目终端目录下输入:数据就会保存到指定目录下了
Scrapy分页数据爬取:
命令介绍:
CrawlSpider:
- 分页数据爬取:
- CrawlSpider使用方法:
- 创建工程:
- scrapy startproject spider_name
- cd进入工程:
- 创建基于CrawlSpider的爬虫文件:
_ scrapy genspider -t crawl spider_routine www.xxx.com
- 执行工程:在终端输入 > scrapy crawl reptile_name
文件介绍
分页爬取的所有东西都和普通爬虫是一样的,就爬虫文件里多出了一个分页爬虫的东西而已。
# decoding:utf-8
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import Test2Item
class SpiderTestSpider(CrawlSpider):
name = 'spider_test' # 爬虫文件的名称
# allowed_domains = ['www.xxx.com'] # 限制可访问的url列表 无用
start_urls = ['https://www.17k.com/chapter/3381946/45309702.html'] # 起始访问的url列表
rules = ( # LinkExtractor:链接提取器 ,用于提取页面中符合自定的正则规则的所有链接
# rule:将链接提取器提取到的链接进行请求处理
# callback:自定请求后的响应数据要传给哪个方法处理
# follow:意思是,要不要将链接提取器作用到,链接提取器提取到的链接上 (分页解析时最有用)
Rule(LinkExtractor(allow=r'/chapter/3381946/\d+.html'), callback='parse_item', follow=True),
)
""" 只要一开起该爬虫项目,就会对第一个页面进行访问,访问到页面之后就会将这个页面内符合自定义的正则规则的链接全部提取出来,
然后交给调度器进行去重,排序处理后继续发起请求,然后将请求到的响应数据交给指定的方法处理,处理完后会继续匹配这个页面中符合正则规则的链接,
会将链接传给调度器,去重后按照队列进行请求处理,这样就可以实现从第一章页面爬到最后一章了。
注意!!!调度器会将所有传过来的链接进行去重处理,只要这次爬虫项目内有发起请求过的链接都不会在出现第二次,
然后调度器会按照传来的先后顺序对url进行排序,排序后在按照先后顺序进行请求处理
"""
def parse_item(self, response):
url = response.url
title = response.xpath('//*[@id="readArea"]/div[1]/h1/text()').extract_first()
item = Test2Item()
item['url'] = url
item['title'] = title
yield item
然后在管道内打印以下传过来的内容,执行程序就是以下内容了