前面一文Scrapy爬虫抓取网站数据已经介绍了如何实现一个爬虫,文中介绍静态bbs网页的抓取。但是,互联网大部分的web页面都是动态的,经常逛的网站例如京东、淘宝等,商品列表都是js,并有Ajax渲染,这样就获取不到网页内容(获取到后台数据后再组合成html展示出来的)。单纯获取页面而没有执行到js的话是无法看到商品数据列表信息的。
那么,我们可以怎么获取这些数据呢?本文以典型的比价网站为例,如:搜狗购物,一淘网,抓取给定商品的价格及其来源网站,如下图。详见完整的爬虫代码。
Search list
抓取内容
抓取前先了解一些概念和工具。
动态网页是指跟静态网页相对的一种网页编程技术。静态网页,随着html代码的生成,页面的内容和显示效果就基本上不会发生变化了——除非你修改页面代码。而动态网页则不然,页面代码虽然没有变,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的。与静态网页相对应的,能与后台数据库进行交互,数据传递。也就是说,网页 URL的后缀不是.htm、.html、.shtml、.xml等静态网页的常见形动态网页制作格式,而是以.aspx、.asp、.jsp、.php、.perl、.cgi等形式为后缀,并且在动态网页网址中有一个标志性的符号——“?”。可以通过以下方式简单验证某网页是否为动态网页。
在页面上右键查看源代码,和右键审查元素所看到的html代码是不一样的,如果后者中能看到商品数据信息,而前者没有的话,就说明这个页面是动态生成的。
Selenium是Thoughtworks公司的一个集成测试的强大工具。Selenium 是 ThoughtWorks 专门为 Web 应用程序编写的一个验收测试工具。与其他测试工具相比,使用 Selenium 的最大好处是: Selenium 测试直接在浏览器中运行,就像真实用户所做的一样。在浏览器加载js后,便可以通过xpath来解析网页了。可以先用 pip install 或 easy_install 安装 Selenium package。
1 | pip install -U selenium |
这里就不详细说明 item
、pipeline
、setting
文件的编写了。如果对这些模块不熟的话可以先看看 Our first spider。
搜索某一款产品,如 Iphone6,我们就可以得到该产品检索结果的起始页面的 start_urls
。但通常情况下,我们可能要得到很多商品相应的信息,那该怎么处理呢?容易想到的是让浏览器模拟我们手动输入,自动响应检索事件,从而得到目标页面的 start_urls
。另一种方法是,我们将目标产品存到一个配置文件中,直接将http://gouwu.sogou.com/shop?query=
ItemList
作为 start_urls
。这里采用后一种方法,简单粗暴有效。
1 2 | #import lstData start_urls = [ ('http://gouwu.sogou.com/shop?query=' searchWord ) for searchWord in lstData().lst] |
首先启用 selenium,这里用本地浏览器 Firefox:
1 2 3 4 5 6 7 | def __init__(self): CrawlSpider.__init__(self) # use any browser you wish self.browser = webdriver.Firefox() def __del__(self): self.browser.close() |
得到所有产品的 start_urls
后,我们便可以通过 Xpath
提取想要的数据了。这里抓取的内容有标题、价格和来源网站。
1 2 3 4 5 | _x_query = { 'title': '//p[@class='title']/a/@title', 'price' : '//span[@class='shopprice font17']/text()', 'name': '//span[@class='floatR hui61 mt1']/text()',##source } |
然后提取页面(下一页),定义提取和过滤 url
:
1 2 3 4 | link_extractor = { 'page_down': SgmlLinkExtractor(allow = '/shop\?query=. ',),#restrict_xpaths = '//a[@class = 'pagination-next']' 'page': SgmlLinkExtractor(allow = '/detail/\d \.html. '), } |
这样我们的 Spider 就差不多定义好了。完整 Spider 程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #-*- coding: utf-8 -*- ''' gouwu.sogou.com Spider, Created on Dec, 2014 #version: 1.0 #author: chenqx @http://chenqx.github.com See more: http://doc.scrapy.org/en/latest/index.html ''' import time from scrapy.selector import Selector from scrapy.http import Request from scrapy.contrib.spiders import CrawlSpider from scrapy.contrib.loader import ItemLoader from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor from etao.items import EtaoItem from etao.lstData import lstData from selenium import webdriver class etaoSpider(CrawlSpider): # name of spiders name = 'Spider' allow_domain = ['gouwu.sogou.com'] start_urls = [ ('http://gouwu.sogou.com/shop?query=' searchWord ) for searchWord in lstData().lst] link_extractor = { 'page': SgmlLinkExtractor(allow = '/detail/\d \.html. '), 'page_down': SgmlLinkExtractor(allow = '/shop\?query=. ',),#restrict_xpaths = '//a[@class = 'pagination-next']' } _x_query = { 'title': '//p[@class='title']/a/@title', 'name': '//span[@class='floatR hui61 mt1']/text()',#//li[2]/a/div[@class='ruyitao-market-name ruyitao-market-name-hightlight']/text() 'price' : '//span[@class='shopprice font17']/text()', # 'price' : '//span[@class = 'price']/text()', } def __init__(self): CrawlSpider.__init__(self) # use any browser you wish self.browser = webdriver.Firefox() def __del__(self): self.browser.close() def parse(self, response): #crawl all display page for link in self.link_extractor['page_down'].extract_links(response): yield Request(url = link.url, callback=self.parse) #start browser self.browser.get(response.url) #loading time interval time.sleep(5) # get the data and write it to scrapy items etaoItem_loader = ItemLoader(item=EtaoItem(), response = response) url = str(response.url) etaoItem_loader.add_value('url', url) etaoItem_loader.add_xpath('title', self._x_query['title']) etaoItem_loader.add_xpath('name', self._x_query['name']) etaoItem_loader.add_xpath('price', self._x_query['price']) yield etaoItem_loader.load_item() |
本文介绍了利用 selenium 实现动态网站数据抓取的一种方法。但需要注意的是 selenium 需要运行本地浏览器,比较耗时,不太适合大规模网页抓取。因此可以尝试其它的 Javascript 加载工具,如 webkit、spynner,也可以调用无界面依赖的浏览器引擎 Casperjs、Phantomjs等。
联系客服