网站采集器自动超文章发布(基于Python的网络数据采集实战(初级篇)中爬取马蜂窝景点页面)

优采云 发布时间: 2021-10-30 04:15

  网站采集器自动超文章发布(基于Python的网络数据采集实战(初级篇)中爬取马蜂窝景点页面)

  一、简介

  比如使用JS脚本来控制部分网页。内容的请求和展示,使得最原创的直接修改静态目标页面的url地址改变页面的方式失效。对于这部分,我在(数据科学学习手册47)基于Python的网络数据采集实战(2)爬马蜂窝景点页面时用户在蜜蜂评论区,也有详细介绍,不过我已经介绍了文章中所有爬虫相关的内容,都离不开开启这样一个过程:

  整理url规则(直接访问静态页面,JS控制的动态页面通过浏览器的开发者工具查找真实的URL和参数)

  |

  伪装浏览器

  |

  使用 urllib.urlopen() 或 requests.get() 启动对目标 url 的访问

  |

  获取返回网页的原创内容

  |

  使用 BeautifulSoup 或 PySpider 解析网页的原创内容

  |

  结合观察到的CSS标签属性等信息,使用BeautifulSoup对象的findAll()方法提取需要的内容,使用正则表达式完成精准提取

  |

  存储在数据库中

  而本文将要介绍的新的网络数据采集工具不再冒充浏览器端,而是基于自动化测试工具selenium结合相应的浏览器驱动,打开真实显式的Browser窗口来完成处理更动态、更灵活的网页的一系列动作;

  二、硒

  2.1 简介

  Selenium 也是 Web 应用程序测试的工具。selenium 测试直接在浏览器中运行,就像真实用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Mozilla Suite、Chrome等。该工具的主要功能是测试与浏览器的兼容性,但由于它能够模拟浏览器的行为,模拟网页点击、拉取跌宕起伏、拖拽元素等,在网络数据上掀开采集一片天地

  2.2 环境设置

  基于Python创建爬虫(这里说的是Python3、Python2,让它退居在历史长河中……)使用selenium创建爬虫程序,我们需要:

  1.安装selenium包,直接pip安装即可

  2.下载浏览器(废话-_-!),以及相应的驱动。本文选择的浏览器为Chrome,需要下载chromedriver.exe。这里是一个收录所有版本的 chromedriver.exe 资源的地址:

  需要注意的是,要下载与您的浏览器版本兼容的资源,这里有一个建议:将您的Chrome浏览器更新到最新版本,然后从上述地址下载最新的chromedriver.exe;下载完成后,将chromedriver.exe放到你的Python根目录下,和python.exe放在一起。比如我把它放在我的anaconda环境中的对应位置:

  

  3. 测试一下~

  完成以上操作后,我们需要检查一下我们的环境是否已经正确设置完成。在您的 Python 编辑器中,编写以下语句:

  from selenium import webdriver

'''创建一个新的Chrome浏览器窗体'''

browser = webdriver.Chrome()

'''在browser对应的浏览器中访问百度首页'''

browser.get('http://www.baidu.com')

  如果执行上述语句后,Chrome浏览器成功打开,访问我们设置的网页,则selenium+Chrome开发环境配置完成;

  2.3 网络数据使用selenium的基本流程采集

  在本文开头,我们总结了网络数据采集的基本流程。下面我们以类似的形式介绍selenium对网络数据采集的基本流程:

  创建浏览器(可能涉及浏览器的一些设置的预配置,比如设置在不需要采集图片时禁止加载图片以提高访问速度)

  |

  使用.get()方法直接打开指定的URL地址

  |

  使用.page_source()方法获取当前主窗口(浏览器中可能同时打开多个网页窗口,则需要使用页面句柄指定我们关注的主窗口网页)页面内容对应到页面

  |

  使用BeautifulSoup或pyspider等解析库解析指定网页内容

  |

  结合观察到的CSS标签属性等信息,使用BeautifulSoup对象的findAll()方法提取需要的内容,使用正则表达式完成精准提取

  |

  存储在数据库中

  可以看出,使用selenium for network data采集和之前的方法最大的区别就是向目标网页发起请求的过程。在使用 selenium 时,我们不再需要伪装浏览器,并且有非常丰富的浏览器动作可以设置。比如我们之前需要翻页,主要是修改url中控制页值对应的参数,所以遇到JS控制的动态网页时,就不用费心去找了。要控制对应资源翻页的实际URL地址,只需要通过selenium内置的丰富定位方法定位页面中的翻页按钮,然后在定位的元素上使用.click()即可实现. 对于真正的翻页操作,

  三、Selenium 常用操作

  3.1 浏览器配置部分

  在调用真正的浏览器对象之前,我们可以根据实际需要配置浏览器的参数。这是由 Selenium 中相应浏览器的 XXXOptions 类设置的。比如本文只介绍Chrome浏览器。我们使用ChromeOptions类中的方法来实现浏览器的预配置,我们来看看ChromeOptions类:

  铬选项:

  ChromeOptions 是一个在 selenium 创建 Chrome 浏览器之前预配置浏览器对象的类。其主要功能包括添加Chrome启动参数、修改Chrome设置、添加扩展应用,例如:

  1.禁止在网页中加载图片

  from selenium import webdriver

'''创建一个新的Chrome浏览器窗体,通过add_experimental_option()方法来设置禁止图片加载'''

chrome_options = webdriver.ChromeOptions()

prefs = {"profile.managed_default_content_settings.images": 2}

chrome_options.add_experimental_option("prefs", prefs)

browser = webdriver.Chrome(chrome_options=chrome_options)

'''在browser对应的浏览器中,以禁止图片加载的方式访问百度首页'''

browser.get('http://www.baidu.com')

'''查看当前浏览器中已设置的参数'''

chrome_options.experimental_options

  

  

  可以看到,经过上面的设置,我们访问的网页中的所有图片都没有加载。这对于提高不需要采集图片资源的任务的访问速度具有重要意义;

  2.设置代理IP

  有时候,面对一些受限的访问频率网站,一旦我们的爬取频率过高,就会导致我们的本地IP地址被暂时封锁。这时候,我们可以采集一些IP代理用来建立我们的代理池。后面我们会单独开一篇博客来详细介绍。以下是如何为我们的 Chrome() 浏览器对象设置 IP 代理的简要演示:

  from selenium import webdriver

'''设置代理IP'''

IP = '106.75.9.39:8080'

'''为Chrome浏览器配置chrome_options选项'''

chrome_options = webdriver.ChromeOptions()

chrome_options.add_argument('--proxy-server=http://{}'.format(IP))

'''将配置好的chrome_options选项传入新的Chrome浏览器对象中'''

browser = webdriver.Chrome(chrome_options=chrome_options)

'''尝试访问百度首页'''

browser.get('http://www.baidu.com')

  但是如果你不是付费高速IP代理,而是从网上所谓的免费IP代理网站中摘取的一些IP地址,那么上述设置后打开的浏览器可能无法显示目标在正常时间的网页内(原因你知道);

  另一种思路:

  除了使用ChromeOptions()中的方法来设置外,还有一个简单直接粗暴的方法。我们可以直接访问当前浏览器设置页面对应的地址:chrome://settings/content:

  from selenium import webdriver

browser = webdriver.Chrome()

'''直接访问设置页面'''

browser.get('chrome://settings/content')

  

  然后用你写的模拟点击规则完成相应的设置内容,这里就不多说了;

  3.2 浏览器运行时的实用方法

  在3.1中介绍的方法之后,浏览器已经预先配置好了,并且成功打开了对应的浏览器,selenium中还是有非常丰富的浏览器方法的。下面我们将讨论一些实用和常用的。类中的方法和变量介绍:

  假设我们构造了一个名为 browser 的浏览器对象,可以使用的方法如下:

  browser.get(url):在浏览器主窗口打开url指定的网页;

  browser.title: 获取当前浏览器主页面的标题:

  from selenium import webdriver

browser = webdriver.Chrome()

'''直接访问设置页面'''

browser.get('https://hao.360.cn/?wd_xp1')

'''打印网页标题'''

print(browser.title)

  

  browser.current_url:返回当前主页面url地址

  browser.page_source:获取当前主界面的页面内容,相当于requests.get(url).content

  browser.close():关闭当前主页面对应的网页

  browser.quit():直接关闭当前浏览器

  browser.maximize_window():最大化浏览器窗口的大小

  browser.fullscreen_window():全屏浏览器窗口

  browser.back():控制当前主页进行back操作(前提是有上一页)

  browser.forward():控制当前主页面进行转发操作(前提是有下一页)

  browser.refresh():控制当前主页面刷新

  browser.set_page_load_timeout(time_to_wait):为当前浏览器设置一个最大页面加载时间容忍阈值,单位为秒,类似于urllib.urlopen()中的timeout参数,即某个界面加载时,持续time_to_wait秒在加载完成之前的时候,程序会报错,我们可以使用错误处理机制来捕捉这个错误,这个方法适合在界面访问超时和假死的情况下长时间采样

  browser.set_window_size(width, height, windowHandle='current'):用于调整浏览器界面的长宽

  关于主页面:

  这是额外的介绍。上一段我们多次提到主页面的概念,因为selenium控制浏览器的时候,无论浏览器打开多少个网页,只有唯一的网页被认为是在主页面上,很多对应的webdriver () 方法也以主页为目标。下面是一个例子。我们以马蜂窝本地旅游页面为例:

  from selenium import webdriver

browser = webdriver.Chrome()

'''访问马蜂窝重庆游记汇总页'''

browser.get('http://www.mafengwo.cn/search/s.php?q=%E9%87%8D%E5%BA%86&t=info&seid=71F18E8D-AA90-4870-9928-2BE01E53DDBD&mxid=&mid=&mname=&kt=1')

  打开目标页面如下:

  

  这里我们手动点击一个游记(模拟点击的方法将在下面介绍),浏览器会立即跳转到一个新页面:

  

  这时候我们运行如下代码:

  '''打印网页标题'''

print(browser.title)

  

  可以看出,虽然在我们的视角下,点击进入一个新的界面,但是当我们使用相应的方法获取当前页面标题的时候,我们还是以之前的页面为对象,这涉及到我们前面提到的主页面问题的解决,当在原页面时,由于一个点击事件而跳转到另一个页面(这里指的是新窗口显示新界面,而不是在原窗口覆盖原页面),在浏览器中主要page of 仍然锁定在原创页面,即 get() 方法跳转到的网页。在这种情况下,我们需要使用网页的句柄来唯一标识每个网页;

  在selenium中,有两种获取网页句柄的方法:

  browser.current_window_handle:获取主页面的句柄,以上面的马蜂窝为例:

  '''打印主页面句柄'''

print(browser.current_window_handle)

  

  browser.window_handles:获取当前浏览器中所有页面的句柄,按打开时间顺序:

  '''打印当前浏览器下所有页面的句柄'''

print(browser.window_handles)

  

  由于句柄相当于网页的ID,我们可以根据句柄将当前主网页切换到其他网页,继续上面的例子。这时候主网页就是.get()方法打开的网页,之前打印的是browser.title。它还指向网页。现在我们使用 browser.switch_to.window(handle) 方法将主网页转移到最近打开的网页,并打印当前主网页的标题:

  '''切换主网页至最近打开的网页'''

browser.switch_to.window(browser.window_handles[-1])

'''打印当前主网页的网页标题'''

print(browser.title)

  

  可以看到,使用主网页切换方式后,我们的主网页就跳转到了指定的网页,这对于特殊网页跳转方式下新打开的网页内容非常有用;

  3.3 页面元素定位

  在介绍 selenium 模拟浏览器行为的本质之前,我们需要知道如何定位网页中的元素。比如我们要定位网页中的翻页按钮,就需要定位翻页按钮的位置。,这里的定位不是指在屏幕平面坐标上的定位,而是基于网页本身的CSS结构。其实selenium中定位网页元素的方法有很多,但是经过我的大量实践,很多方法都没有效果,果然只有基于xpath的定位方法很方便,定位也很准确方便,所以本文就不浪费时间介绍其他效果不太好的方法了,直接介绍基于xpath的定位方法。

  关于 xpath:

  xpath 是一种用于在 xml 文档中查找信息的语言。要在selenium中定位网页元素,我们只需要掌握xpath路径表达式即可;

  Xpath 使用路径表达式来标识 xml 文档中的节点或节点集。让我们从一个示例开始,以了解 xpath 路径表达式:

  以马蜂窝游记页面为例:

  from selenium import webdriver

browser = webdriver.Chrome()

'''访问马蜂窝重庆游记汇总页'''

browser.get('http://www.mafengwo.cn/search/s.php?q=%E9%87%8D%E5%BA%86&t=info&seid=71F18E8D-AA90-4870-9928-2BE01E53DDBD&mxid=&mid=&mname=&kt=1')

  通过浏览器的开发者工具,我们找到了“下一页”按钮元素在CSS结构中的位置:

  

  先写出元素的完整xpath路径表达式:

  //div/div/a[@class='ti next _j_pageitem']

  然后我们使用基于xpath的定位方法来定位按钮的位置并模拟点击:

  '''定位翻页按钮的位置并保存在新变量中'''

ChagePageElement = browser.find_element_by_xpath("//div/div/a[@class='ti next _j_pageitem']")

'''对按钮位置变量使用click方法进行模拟点击'''

ChagePageElement.click()

  上述代码运行后,我们的浏览器执行一次模拟点击翻页按钮,实现翻页:

  

  下面我们来介绍一些xpath路径表达式的基础知识:

  nodename:表示节点的标签名称

  /:父节点和子节点之间的分隔符

  //: 代表父节点和下级节点之间的几个中间节点

  []:指定结束节点的属性

  @:在[]中指定属性名称和对应的属性值

  xpath路径表达式中还有很多其他的内容,但是在selenium中进行基本元素定位就足以理解上面的规则了,所以我们上面例子中的规则表示定位

  几个节点-

  ……

  ……

  ……

  ……

  这样,基于browser.find_element_by_xpath()和browser.find_elements_by_xpath(),我们就可以找到页面中的单个唯一元素或多个相同类型的元素,然后使用.click()方法完成页面中的任意元素页面模拟点击;

  3.4 基本浏览器动作模拟

  除了使用元素.click()控制上一节介绍的点击动作外,selenium还支持丰富多样的其他常用动作,因为这篇文章是我介绍selenium的第一部分,下面只介绍两个常用动作,更复杂的组合动作将在下面文章中介绍:

  模拟网页衰落:

  很多时候我们会遇到这样动态加载的网页,比如光点壁纸的各个壁纸板块。以下是景观部分的示例:

  

  这个网页的特点是,在大多数情况下,没有翻页按钮,但是用户将页面滑动到底部后会自动加载下一页的内容,并且这个机制固定几次后,将被混合。翻页前必须点击的按钮,我们可以使用selenium中的browser.execute_script()方法传入JavaScript脚本来执行浏览器动作,然后实现向下滑动功能;

  幻灯片底部对应的JavaScript脚本是'window.scrollTo(0, document.body.scrollHeight)',我们使用如下代码实现连续滑动,并及时捕捉翻页按钮点击(使用错误处理机制实现):

  from selenium import webdriver

import time

browser = webdriver.Chrome()

'''访问光点壁纸风景板块页面'''

browser.get('http://pic.adesk.com/cate/landscape')

'''这里尝试的时候不要循环太多次,快速加载图片比较吃网速和内存'''

for i in range(1, 20):

'''这里使用一个错误处理机制,

如果有定位到加载下一页按钮就进行

点击下一页动作,否则继续每隔1秒,下滑到底'''

try:

'''定位加载下一页按钮'''

LoadMoreElement = browser.find_element_by_xpath("//div/div[@class='loadmore']")

LoadMoreElement.click()

except Exception as e:

'''浏览器执行下滑动作'''

browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')

time.sleep(1)

  模拟输入:

  有时,我们需要对界面中出现的输入框,即标签所代表的对象进行模拟输入操作。这时候我们只需要定位到输入框对应的网页对象,然后使用browser.send_keys(输入内容)来回输入框内添加文字信息即可。下面是一个简单的例子。我们从百度首页开始,模拟点击登录-点击注册-在用户名输入框中输入指定的文字内容,这样一个简单的过程:

  from selenium import webdriver

browser = webdriver.Chrome()

'''访问百度首页'''

browser.get('http://www.baidu.com')

'''对页面右上角的登陆超链接进行定位,这里因为同名超链接有两个,

所以使用find_elements_by_xpath来捕获一个元素列表,再对其中

我们指定的对象执行点击操作'''

LoginElement = browser.find_elements_by_xpath("//a[@name='tj_login']")

'''对指定元素进行点击操作'''

LoginElement[1].click()

'''这段while语句是为了防止信息块没加载完成导致出错'''

while True:

try:

'''捕获弹出的信息块中的注册按钮元素'''

SignUpElement = browser.find_elements_by_xpath("//a[@class='pass-reglink pass-link']")

'''点击弹出的信息块中的注册超链接'''

SignUpElement[0].click()

break

except Exception as e:

pass

'''将主网页切换至新弹出的注册页面中以便对其页面内元素进行定位'''

browser.switch_to.window(browser.window_handles[-1])

while True:

try:

'''对用户名称输入框对应元素进行定位'''

InputElement = browser.find_element_by_xpath("//input[@name='userName']")

'''模拟输入指定的文本信息'''

InputElement.send_keys('Keras')

break

except Exception as e:

pass

  

  以上就是上一篇关于selenium的网络数据采集的内容,剩下的内容我会挤时间继续整理介绍,敬请期待。如有错别字,希望大家指出。

  发表于 @ 2018-09-07 15:24 Feifry 阅读(1587)评论(0)编辑

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线