使用多个Python库开发网页爬虫(二)

使用正则表达式

在之前的文章中,我们讨论过正则表达式,正则可以用来识别常见的模式(电子邮件,URL,手机号等),功能强大。

幸运的是,BeautifulSoup也支持正则这一功能,我们可以使用正则表达式来匹配特定的标签。

想像一下,我们想抓取一些链接,匹配一个特定的模式,如属于内部的链接,或者特殊的外部链接,或者抓取一些特定路径的图片。

使用正则表达式则很轻松的实现这些工作。

importre tags = res.findAll("img", {"src":re.compile("\.\./uploads/photo_.*\.png")})

上面的代码会替换掉../uploads…之类的路径更换为img标签。

我挺喜欢Python的页面抓取。上面的只是个简单例子,这里向您展示的只是和BeautifulSoup结合使用正则表达式的强大功能之一。

使用JavaScript开发网页抓取工具

假如你要抓取的页面之前会有一个预加载,可能会把你重定向另一个页面,而URL此时却没有变,有一些页面使用了Ajax或者使用React技术做了异步处理。

这时我们使用常规的抓取是取不到任何内容的,在服务器端,没有需要的JavaScript内容,需要浏览器端运行JavaScript来加载内容。

这时,我们需要一个名叫Selenium的Python库来处理。Selenium不包含自己的浏览器,因此也需要安装第三方浏览器(或Web 驱动)才能正常工作。浏览器可以从Chrome、Firefox、Safari或Edge中选择其一。

比如我们已经在本地安装了这些浏览器的其中一个,假设为Chrome,Selenium可以打开浏览器的一个标签并加载页面。接下来,我们就可以进行抓取操作或者与网页进行交互。

使用Selenium抓取网页

首先安装Selenium库:

$pipinstall selenium

然后,请到https://sites.google.com/a/chromium.org/chromedriver/downloads下载Chrome驱动程序,设置为全局系统路径。

现在,我们可这样加载一个需要的网页。请看如下代码:

fromselenium import webdriver

browser= webdriver.Chrome()

browser.get("https://www.python.org/")

nav =browser.find_element_by_id("mainnav")

print(nav.text)

以上代码运行结果如下:

是不是很简单,对吧?

在这里,我们没有和页面交互,暂时还没有领略到Selenium的力量,请稍候。

显示抓取的交互效果

你可能和我一样喜欢用浏览器驱动,也有人喜欢让程序在后台跑,不需要了解它的运行情况。

为了这个目的,我们有一个称为PhantomJS的好工具,可以不用打开任何浏览器的情况下运行代码。它能够让我们与页面中令人头疼的Cookies和JavaScript进行交互,可以像使用BeautifuSoup一样抓取页面中的内容和元素。

PhantomJS的下载地址为:http://phantomjs.org/

下载完毕后,请把它放在你的系统路径中,我们用它来做Selenium的网络驱动程序。

现在,让我们就使用PhantomJS显示运行交互,和使用Chrome的Web驱动一样。如下代码:

fromselenium import webdriver

browser= webdriver.PhantomJS()

browser.get("https://www.python.org/")

print(browser.find_element_by_class_name("introduction").text)browser.close()

以上代码运行结果如下:

看起来很棒!它工作的不错。我们可以通过多种方式来访问HTML元素,例如:

browser.find_element_by_id("id")browser.find_element_by_css_selector("#id")browser.find_element_by_link_text("Click Here")browser.find_element_by_name("Home")

这些函数只返回一个元素。我们可以让它返回多个元素。如下代码:

browser.find_elements_by_id("id")browser.find_elements_by_css_selector("#id")browser.find_elements_by_link_text("Click Here")browser.find_elements_by_name("Home")

我们可以使用page_source上返回内容使用。如下:

fromseleniumimport webdriver

from bs4 import BeautifulSoup

browser = webdriver.PhantomJS()

browser.get("https://www.python.org/")

page =BeautifulSoup(browser.page_source,"html5lib")

links = page.findAll("a") for linkin links:

print(link) browser.close()

运行结果如下:

感受到Python抓取网页的力量?我们再了解更多。

抓取iFrame内容

我们要抓取的页面可以包含一个iframe,这时我们无法获取到iframe的内容,需要清除掉iframe源文件。

可以用Selenium通过切换到想要删除的iframe来抓取。如下:

fromselenium import webdriver

browser = webdriver.PhantomJS()

browser.get("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")

iframe =browser.find_element_by_tag_name("iframe")browser.switch_to.default_content()

browser.switch_to.frame(iframe)

iframe_source = browser.page_source

print(iframe_source) #returns iframe source

print(browser.current_url) #returns iframe URL

运行结果如下:

使用BeautifulSoup抓取iframe内容

在BeautifulSoup中使用find函数获取ifame的URL,然后再抓取。

fromurllib.request

importurlopen from urllib.error

importHTTPError from urllib.error

importURLError from bs4

importBeautifulSoup

try:

html=urlopen("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")

exceptHTTPError as e: print(e)

exceptURLError: print("Server down or incorrect domain")

else:res = BeautifulSoup(html.read(), "html5lib")

tag =res.find("iframe")

print(tag['src'])#URl of iframe ready for scraping

真的很棒!这就是Python网页抓取的力量。我们还有更多的选择。

使用Selenium和PhantomJS处理Ajax调用

在网页调用Ajax后,可以用Selenium来抓取内容。就如同点击获取异步的内容按钮一样。如下例:

fromselenium import webdriver

importtime browser = webdriver.PhantomJS()

browser.get("https://www.w3schools.com/xml/ajax_intro.asp")browser.find_element_by_tag_name("button").click()

time.sleep(2)#Explicit wait

browser.get_screenshot_as_file("image.png")

browser.close()

在此处,我们抓取了一个页面,其中包含一个按钮,我们点击按钮,通过Ajax调用获取文本,然后我们又保存了该页面的屏幕截图。

这里有一个小问题,就是要有一个等待时间。页面加载不能超过2秒,但是有时候网络原因或者服务器响应时间,会让这个加载时间延长。下面我们使用相应的解决方案。

等待Ajax调用完毕(隐式等待)

其实最好的解决方案是检查最后一页是否存在HTML元素,如果存在,意味着Ajax调用已完成。

如下代码:

fromselenium import webdriver

import expected_conditions as EC

browser = webdriver.PhantomJS()

browser.get("https://resttesttest.com/")browser.find_element_by_id("submitajax").click()

try:

element = WebDriverWait(browser,10).until(EC.text_to_be_present_in_element((By.ID, "statuspre"),"HTTP200 OK"))

finally:browser.get_screenshot_as_file("image.png")

browser.close()

结果为:

在此处,我们触发一个Ajax按钮,调用REST接口并返回JSON格式结果。

如果10秒内返回“HTTP 200 OK”,我们检查div元素文本,然后再接结果页保存为一个图片,如上图所示。

我们还可以做更多事情,比如:

使用EC.url_change()更改网址

使用EC.new.window_is_opened()打开新窗口

使用EC.title.is()更改页面标题

如果有任何页面重定向,则可以查看标题或URL是否有更改。当然,还有很多条件可以检查,这里仅做抛砖引玉,告诉大家有很多能力。非常爽!

处理Cookies

有时我们抓取某些网站,需要考虑到Cookie,这点很重要。也许你需要删除一些cookie,或者需要把它保存到一个文件中,用来做自动登录。

还有很多场景,让我们一起看如何处理cookie。

要获取当前网站的Cookie,可以使用get_cookie()函数。如下:

fromselenium

importwebdriver

browser= webdriver.PhantomJS()

browser.get("https://www.21cto.com/")

print(browser.get_cookies())

运行结果如下:

要删除cookie,可以用delete_all_cookies()函数。如下代码:

fromselenium import webdriver

browser= webdriver.PhantomJS()

browser.get("https://www.21cto.com/")

browser.delete_all_cookies()

小结

在本篇,我们一起讨论了Python的网页抓取以及如何解析网页,正如我们看到了的,抓取的工作就是为解析网页并从中提取数据。

网页抓取收集页面中的每一个链接,通过链接抓取到相关层次的页面,相当于索引的目的,就像Google和其它搜索引擎一样。

编译:前端老白

来源:DZone.com

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171215B03QN400?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券