当前位置: 澳门新濠3559 > 编程 > 正文

为了更方便的在内网环境下快速的查阅资料,更

时间:2019-11-09 19:36来源:编程
  更新 7月16日18点 本文是我接触爬虫以来,第三套爬虫的代码记录博客。 本文主要是记录淘宝搜索美食的页面信息,工具是selenium和phantomJS,框架PyQuery其实对于以上框架或者工具,仅

 

更新 7月16日18点
  • 本文是我接触爬虫以来,第三套爬虫的代码记录博客。
  • 本文主要是记录淘宝搜索美食的页面信息,工具是selenium 和 phantomJS,框架PyQuery其实对于以上框架或者工具,仅仅停留在使用的初级阶段,具体可以参看崔老师的相关博客:
    Python爬虫利器四之PhantomJS的用法
    Python爬虫利器五之Selenium的用法
    Python爬虫利器六之PyQuery的用法

一般的的静态HTML页面可以使用requests等库直接抓取,但还有一部分比较复杂的动态页面,这些页面的DOM是动态生成的,有些还需要用户与其点击互动,这些页面只能使用真实的浏览器引擎动态解析,Selenium和Chrome Headless可以很好的达到这种目的。

由于需要在公司的内网进行神经网络建模试验(),为了更方便的在内网环境下快速的查阅资料,构建深度学习模型,我决定使用爬虫来对深度学习框架keras的使用手册进行爬取。

现在不会自己写代码调用API的同志们可以直接访问咯

地址 datastack.cc/design
更新一张预览图:

澳门新濠3559 1

澳门新濠3559 2

思路

  • 模拟在淘宝的搜索框填写关键词,然后搜索
  • 模拟数据加载完毕后,点击下一页操作
  • 数据加载结束以后利用PyQuary进行数据解析提取
  • 存储到mongoDB
  • 代码细节优化

Headless Chrome

Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有Chrome支持的特性,在命令行中运行你的脚本。以前在爬虫要使用Phantomjs来实现这些功能,但Phantomjs已经暂停开发,现在可以使用Headless Chrome来代替。

使用很简单,保证chrome命令指向chrome浏览器的安装路径,ubuntu下为google-chrome。

输出html:

google-chrome --headless --dump-dom https://www.cnblogs.com/

将目标页面截图:

google-chrome --headless --disable-gpu --screenshot https://www.cnblogs.com/  # 规定大小google-chrome --headless --disable-gpu --screenshot --window-size=640,960 https://www.cnblogs.com/

 保存为pdf:

google-chrome --headless --disable-gpu --print-to-pdf https://www.cnblogs.com/

 以上文件会保存于当前目录。

还可以使用--remote-debugging-port参数进行远程调试:

google-chrome --headless --disable-gpu --no-sandbox --remote-debugging-port=9222 --user-data-dir='/d/cnblogs' http://www.cnblogs.com

 --user-data-dir参数可以设定保存目录,--user-agent参数可以设定请求agent。上述的命令打开了一个websocket调试接口对当前Tab内页面的DOM、网络、性能、存储等等进行调试。

打开

还有一系列地址:

[ {   "description": "",   "devtoolsFrontendUrl": "/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/5C7774203404DC082182AF4563CC7256",   "id": "5C7774203404DC082182AF4563CC7256",   "title": "博客园 - 代码改变世界",   "type": "page",   "url": "https://www.cnblogs.com/",   "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/5C7774203404DC082182AF4563CC7256"} ]

: 查看浏览器版本信息

{   "Browser": "HeadlessChrome/71.0.3578.98",   "Protocol-Version": "1.3",   "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/71.0.3578.98 Safari/537.36",   "V8-Version": "7.1.302.31",   "WebKit-Version": "537.36 (@15234034d19b85dcd9a03b164ae89d04145d8368)",   "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/browser/ed156c0d-805c-4849-99d0-02e454260c17"}

: 新开Tab打开指定地址

: 关闭指定Tab,close后为tab页面的id

: 切换到目标Tab

tab页面信息中有一个devtoolsFrontendUrl,是开发者工具的前端地址,可以打开:

http://127.0.0.1:9222/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/CE2E627C634EAAE3CE9193DC374C7B4A

在开发者工具里切换到Performance,勾选Screenshots,点刷新图标,重新加载完成就可以看到逐帧加载的截图:

澳门新濠3559 3

keras中文文档的地址是 ,是基于英文原版使用手册,由国内众多学者进行翻译所得,方便大家在学习和工作中快速的进行查阅。

更新 7月16日12点

工具安装

  • 安装 selenium
    brew install selenium-server-standalone
  • 安装PyQuery
    sudo easy_install pyquery
  • 安装phantomjs
    brew install phantomjs

Selenium

Selenium 是用于测试 Web 应用程序用户界面的常用框架,它支持各种浏览器,包括 Chrome,Safari,Firefox 等,支持多种语言开发,比如 Java,C,Ruby等等,当然也有Python。

pip install selenium

使用时还需要下载浏览器驱动,以chromedriver为例,下载地址:

chromedriver

国内镜像:

镜像

下载时注意与电脑的chrome版本保持一致,然后将chromedriver置于环境变量之中。

打开一个淘宝商品网页:

from selenium import webdriverbrowser = webdriver.Chrome()browser.get('https://market.m.taobao.com/app/dinamic/h5-tb-detail/index.html?id=568217064643')

浏览器会自动打开并访问网页。

使用headless模式:

from selenium import webdriverchrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--no-sandbox')chrome_options.add_argument('--headless')chrome_options.add_argument('--disable-gpu')browser = webdriver.Chrome(options=chrome_options)browser.get('https://market.m.taobao.com/app/dinamic/h5-tb-detail/index.html?id=568217064643')data = browser.page_source

page_souce属性可以获取html网页源码。

可以看到获取的源码都是些js与css语句,dom并未生成,需要模拟浏览器滚动来生成dom:

for i in range:    browser.execute_script(        "window.scrollTo(0, document.body.scrollHeight/10*%s);" % i    )    time.sleep

execute_script方法可以用来执行js脚本。

现在获取的源码基本是完整的,还存在一些小问题,比如网页为了让img延迟加载,img的地址是放在data-img属性上的,等到浏览器滑动至图片时才修改src属性,可以使用pyquery修改:

import timefrom selenium import webdriverfrom pyquery import PyQuery as pqbase_dir = os.path.dirnamechrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--no-sandbox')chrome_options.add_argument('--headless')chrome_options.add_argument('--disable-gpu')browser = webdriver.Chrome(options=chrome_options)# browser.implicitly_waitbrowser.get('https://market.m.taobao.com/app/dinamic/h5-tb-detail/index.html?id=568217064643')for i in range:    browser.execute_script(        "window.scrollTo(0, document.body.scrollHeight/10*%s);" % i    )    time.sleepdata = browser.page_source.encodedoc = pqfor img in doc:    img = pq    if img.attr['data-img']:        img.attr.src = img.attr['data-img']data = doc.html(method='html').replace('src="//', 'src="http://')f = open(os.path.join(base_dir, 'detail.html'), 'w')f.write(data.encodef.close()

 保存为html后打开可以看到网页爬取成功。

selenium还提供了很多element提取接口:

提取单个element:

elem = browser.find_element_by_id("description")

提取多个:

elem = browser.find_elements_by_class_name("detail-desc")

 

现在我们可以愉快的使用了,flask API和后台服务已经部署在了服务器上(新加坡)!!!

地址 http://api.datastack.cc

恩,更新一下,目前已经可以在HTML页面进行数据展示了:

澳门新濠3559 4

web界面运行效果图

澳门新濠3559 5

配图纯属为了好看

利用 selenium模拟淘宝操作

使用selenium的大致思路根据CSS选择器或者id之类的定位到具体的控件,然后给控件实现赋值或者点击等操作。

批量爬取

可以使用concurrent.futures 线程池进行多线程批量爬取:

# -*- coding: utf-8 -*-import threadingimport timeimport osfrom concurrent.futures import ThreadPoolExecutor, as_completedfrom pyquery import PyQuery as pqclass TaobaoCrawler:    def __init__(self, ids):        self.ids = ids        self.browsers = {}        self.timeout_spus = []        self.url = 'https://market.m.taobao.com/app/dinamic/h5-tb-detail/index.html?id='    def _create_new_browser:        from selenium import webdriver        chrome_options = webdriver.ChromeOptions()        chrome_options.add_argument('--no-sandbox')        chrome_options.add_argument('--headless')        chrome_options.add_argument('--disable-gpu')        # chrome_options.add_argument('--blink-settings=imagesEnabled=false')        browser = webdriver.Chrome(options=chrome_options)        return browser    def get_browser:        current_thread_id = threading.currentThread().ident        existed = self.browsers.get(current_thread_id)        if existed:            return existed        new_browser = self._create_new_browser()        self.browsers[current_thread_id] = new_browser        return new_browser    def close_browsers:        for _, browser in self.browsers.iteritems():            browser.quit()        self.browsers = {}    def scroll_browser(self, browser, num):        '''模拟浏览器滚动 保证js全部执行完成'''        for i in range:            browser.execute_script(                "window.scrollTo(0, document.body.scrollHeight/%d*%d);" % (                    num, i)            )            time.sleep    def handle_detail_doc(self, detail):        doc = pq        for img in doc:            img = pq            if img.attr['data-img']:                img.attr.src = img.attr['data-img']        detail = doc.html(method='html')        detail = detail.replace('src="//', 'src="http://')        return detail    def crawl_taobao_detail(self, taobao_id):        browser = self.get_browser()        url = self.url + str(taobao_id)        browser.execute_script("window.stop        browser.get        self.scroll_browser(browser, 20)        data = browser.page_source.encode        data = self.handle_detail_doc        return taobao_id, data    def start_crawl:        if not self.ids:            return        with ThreadPoolExecutor(max_workers=4) as executor:            futures = [executor.submit(self.crawl_taobao_detail, _)                       for _ in self.ids]            for task in as_completed:                if task.done():                    taobao_id, data = task.result()                    base_dir = os.path.dirname                    f = open(os.path.join(base_dir, str(taobao_id) + '.html'), 'w')                    f.write(data.encode                    f.close()        self.close_browsers()def test_crawl():    ids = [568217064643, 584126060993, 581555053584, 581002124614]    c = TaobaoCrawler    c.start_crawl()if __name__ == '__main__':    test_crawl()

  

在编写爬虫之前,我们需要对网站的源码进行分析,以确定抓取策略。

我在说什么

声明:
1.我不是一个标题党
2.我一般只提供干货

事实上,我实在干这样一件事,他大概分为如下几个步骤:

selenium的简单配置

  • 导入框架
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
  • 加载浏览器驱动,本例中使用谷歌浏览器,使用前请确认已经安装
    chromedriver,关于配置可以自行Google或者访问我的博客

    澳门新濠3559 6

    支持的浏览器

澳门新濠3559 7

选择元素css

# 加载驱动
browser = webdriver.Chrome()

此时代码运行可以呼起一个空置的谷歌浏览器

  • 设置等待超时时间:在规定时间内未能加载相应控件将报错
wait = WebDriverWait(browser, 10)
  • 通用写法
wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))
        )
  • 代码分析

    • EC 为from selenium.webdriver.support import expected_conditions as EC
    • EC后边的是选择条件,即什么时候可以选择控件,例中条件为控件完全展示,其他选择条件请看下面 EC选择条件
    • By 为from selenium.webdriver.common.by import By
    • By后边的是根据什么元素选择控件,可以使id 或者css等等,后边的参数为具体的元素值
  • EC选择条件

title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present
  • By参数类型
    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

首先,网页分为左右两个部分,并且网站的大部分有效地址基本上都是集中在页面左侧的索引中,以<li class="toctree-l1 "></li>标签进行包围。

一、获取一些优秀的设计素材的数据

模拟关键字填写及搜索

  • 输入框的EC条件为presence_of_element_located,然后利用其css选择器,并复制其id
  • 确定按钮EC条件为element_to_be_clickable同样选择其css值
  • 输入框内通过send_keys传入搜索词
  • 确定按钮调用click()方法
  • 其他的方法参见文档
  • 坑:send_keys输入关键字的时候,在Python2.7的环境中,如果直接用字符串会报错
    UnicodeDecodeError: 'utf8' codec can't decode byte 0xe7in position 0: unexpected end of data
    可以通过解码进行修复"美食".decode(encoding="utf-8")
browser.get("https://s.taobao.com")
    # selenium处理页面等待的方法
    # 设置一下需要监听的元素,可以通过id或者能唯一确定元素的属性
    # EC是选择条件点后边的是条件,我把条件记录在简书里
    # 我们通过页面元素,查找到输入框,我们利用css样式去确定,并利用css选择器去获取
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))
        )

        # 然后监听按钮,条件是以可以点击判断其加载完成
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_SearchForm > div > div.search-button > button"))
        )

        # 调用selenium的API来给搜索框输入内容,然后按钮追加点击方法
        # send_keys添加参数
        input.send_keys(KEYWORD)
        # 添加点击方法
        submit.click()

澳门新濠3559 8

二、存储和筛选这些数据

获取宝贝页面的宝贝总页数

  • 监听翻页控件加载完,以显示共xx页显示完全为依据
  • EC的条件也就是presence_of_element_located,同样利用其css选
    择器
  • 将返回页数作为返回值返回
 total = wait.until(
       EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total"))
  )
return total.text

根据网站的这个特征,我们可以不使用传统的 URL管理器+网页下载器+解析器 的传统递归爬取模式,化繁为简,一次性的获取索引中所有的待爬取url。

三、编写一套API提供数据

实现翻页

翻页功能有种实现方式

  • 点击下一页,实现翻页,但是如果发生错误不易差别是具体页数

  • 输入页码,点击确定,可以清楚的知道具体跳转了那一页,翻页后确定当前面是否加载完,主要看页码当时是否为高亮状态

![](https://upload-images.jianshu.io/upload_images/954728-4483a276f47d8342.png)
  • 定义一个以页码作为参数的函数

  • 获取页码户输入框架,获取确定按钮,输入框填入参数,然后点击确定实现翻页,与搜索功能相同

  • 确定当前页码的高亮状态来

def get_next_page(page_number):
    print(u"正在翻页")
    try:
    # 拿到输入框 和确定 按钮,然后输入页码
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.form > input"))
        )

        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit"))
        )
        input.clear()
        input.send_keys(page_number)
        submit.click()

        # 翻页后确定当前面是否加载完,主要看页码当时是否为高亮状态
        text = wait.until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > ul > li.item.active > span"), str(page_number))
        )
        get_product()
    except TimeoutException:
        print("get_next_page超时")
        get_next_page(page_number)

其次,该页面的url不同于我们平时所浏览的.html或.jsp文件,通过浏览器的查看元素操作,可以知道该url所对应的是一个事件。应该是类似于一个action指令,服务器根据这个传入参数,来动态的返回页面。

四、编写一个网页调用API 展现数据

PyQuery实现页面解析

对于PyQuery(以下简称pq)的用法目前完全懵逼,完全是跟着视频敲的,只知道类似于jQuery,根据id或者css样式去获取查找元素,页面结果见下图,通过idmainsrp-itemlist的,然后css样式为items获取商品列表,最后通过css样式为items,然后每个商品的信息

澳门新濠3559 9

网页结构图

  • 没啥说的直接上代码
'''
3.解析页面,获取美食信息
'''
def get_product():
    print("正在获取产品")
    # 页面记载结束:主要是看商品信息的大节点是不是加载完了
    wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-itemlist .items .item"))
    )
    # 获取页面内容
    html = browser.page_source
    # 通过PyQuery解析页面
    doc = pq(html)
    # 根据节点获取美食的集合
    items = doc("#mainsrp-itemlist .items .item").items()
    # 遍历 获取各值
    for item in items:
        product = {
            # 获取img标签下的src属性
            "image": item.find(".pic .img").attr("src"),
            "price": item.find(".price").text(),
            "deal": item.find(".deal-cnt").text()[:-3],
            "title": item.find(".title").text(),
            "shop": item.find(".shop").text(),
            "location": item.find(".location").text()
        }
  • 在第一次加载页面方法时,也就是第一页的时候调用此方法,获取第一页的数据
  • 在翻页的时候也要调用此方法

澳门新濠3559 10

五、编写iso和android客户端展现数据

应用场景:
当你在闲暇的时候,打开手机或者网页,查看一下最近有没有什么好的设计素材或者比较感兴趣的HTML页面。
恩,你可能看到很多,突然发现一个让你眼前一亮的,然后你手藏了他。
有一天你正在写一个HTML页面或者设计产品原型,突然,你的脑子里闪过一些东西,于是你打开了你的手机查看了一下收藏夹......

接下来,我们就来看看,如何实现:

存储到mongoDB

与第一篇爬取头条数据一样,需要单独创建配置文件,然后创建俩呢及,创建数据库,存储数据,有一点着重提示的是,在代码运行存储数据的时候,一定要记得开启mongoDB的服务,不然会报一些莫名其妙的错误

  • 配置文件代码
MONGO_URL = "localhost"
MONGO_DB = "Taobao"
MONGO_TAB = "TbCate"
  • 创建数据库连接
# 创建数据库链接
client = MongoClient(MONGO_URL)
# 创建数据库
db = client[MONGO_DB]
  • 存储数据
'''
4.存储数据
'''
def save_to_mongo(result):
    try:
        if db[MONGO_TAB].insert(result):
            print("正在存储到mongDB")
    except Exception:
        print("存储失败",result)

为了正确的获取动态页面的内容,我们设计使用基于selenium+phantomJS的python语言爬虫来完成全站爬取任务。

数据获取

首先,数据主要是从各大免费的设计素材资源网站拿到的,这需要用到python爬虫。
其次,这类网站大量的使用了JS来加载内容,我选择selenium+phantomJS渲染JS。
最后,从爬取到的内容内获取想要的,我选择用pyquery来获取html节点(不要问为什么,因为我习惯用jquery!)

代码整体串接

def main():
    try:
        # 获取总页数
        totoal = search()
        # 获取数字,过滤汉字
        pattern = re.compile(r"(d+)")
        match = re.search(pattern, totoal)
        # 遍历获取所有的页面
        for i in range(2,int(match.group(1)) + 1):
            get_next_page(i)
        # 数据获取结束以后关闭浏览器
    except Exception:
        print("出错了")
   # 用完后,必须关闭浏览器
    finally:
        browser.close()

selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等[1]。

存储数据

引入phantomJS

我感觉如果遇到一个具体类似淘宝宝贝数据爬取的需求的话,可能的大致思路是先通过浏览器去模拟数据,成功以后,引入phantomJS去静默爬取数据

  • 配置phantomJS
# 将Google浏览器换成PhantomJS
browser = webdriver.PhantomJS()
# 修改弹框大小
browser.set_window_size(1400,800)
  • PhantomJS的一些高级配置,详见官网
    • 在配置文件中简单进行配置
# phantomJS的高级用配置:不加载图片,加缓存
SEARVICE_ARGS = ["--load-images=false","--disk-cache=true"]
  • 代码中引入
browser = webdriver.PhantomJS(service_args=SEARVICE_ARGS)

phantomJS是一个基于 WebKit(WebKit是一个开源的浏览器引擎,Chrome,Safari就是用的这个浏览器引擎) 的服务器端 JavaScript API,python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。

数据结构

数据结构很简单,我不过就是想获取一张预览图,一个预览地址(或者下载地址),还有标题!
一条数据大概会是这样:

{
  "download": "http://www.doooor.com/thread-2762-1.html",
  "preview": "http://img.doooor.com/img/forum/201404/16/173909sczpof6sf26eckcf.jpg.thumb.jpg",
  "title": "STARS TOUCH 完全扁平化网页设计"
}

一些注意点

  • selenium 等待控件加载的时候,容易发生超时问题,所以要加异常处理,一般超时后都是在调用一遍方法
  • 引入 PhantomJS以后,browser.close()会报错,所以也要加异常处理,在finally后边关闭
  • 存储到mongoDB的时候一定要先开启mong服务
  • 本博客对PyQueryPhantomJS没有进行详细的讲解,因为本人基础薄弱,但是给了一些博客链接,待到本人学习以后会将博客进行完善,另外本博客在GitHub的源码README中同步更新了
  • 代码地址

关于selenium与phantomJS的用法在网上有很多讲解,本文不再赘述,仅针对该全站爬取任务进行阐述。

数据持久化

我们对数据的存储要求不是很高,因为最近在学习redis,所以就用redis,利用快照持久化!

动态页面与静态页面的分析

爬虫的框架

一、我不懂什么框架,而且总体来说,要爬取得网站就那几个。自己编写一下规则就好了。
二、避免重复工作,用redis来存储待爬和爬过的url。
三、分布式? 哈哈,也许,可能大概是支持的吧。
四、效率?使用了selenium和phantomJS,貌似不用谈效率了,不过有些优化的小知识啦!
五、我是怎么实现的:
首先,我定义了一个爬虫服务 service.py,主要作用是连接redis,开始爬取工作,记录工作内容和工作结果。
然后,我写了一个爬虫工具 servicetools.py, 主要作用是模拟浏览器访问url,查找需要的元素和内容。

不同于单个网页的下载,全站爬取的难点在于如何在爬取之后保存网页之间的正确调用关系(即点击超链接能够正确的进行页面跳转)。在目标网站 keras中文文档中,服务器通过传递进来的action,使用servlet进行应答,返回对应的页面(笔者web开发的功底不牢固,只能描述大概流程,服务器运行具体细节难以描述清楚  =。=#  )。而将这些动态页面的信息以静态方式进行存储后,只有把它们放在正确的相对路径下,才能够在流量器中正常使用,因此在下载页面的时候,需要完成以下两个工作: 

澳门新濠3559,service.py 管理者-劳动者模式 (管理者Master发布任务,劳动者Work进行具体工作.)

管理者维护一个Redis 的 List 按照先进先出的模式, 每次发布一个url出去
劳动者接收到管理者的url,开始执行网页爬取工作,工作完成后 管理者pop掉这个url
劳动者如果获取的数据是url,则封装成list 提交给管理者, 管理者挨个push url.

工作1.获取页面所在的相对路径,并且给页面命名。通过对页面的源代码进行浏览,我们可以发现,每个页面的url就是它以/latest/为根目录的相对路径。

servicetools.py(具体的网页爬取工作)

使用phantomJS和selenium结合,使用pyquery进行节点和内容的获取,不同的网站需要不同的规则。

澳门新濠3559 11

目前实现的功能 和存在问题:

总体来说,运行良好,效率足够(根本不是实时系统嘛)!
额,比较费内存,可以在晚上睡觉之前执行,偶尔会出现假死,主要是phantomJS的优化没做!
如果程序异常推出,再次启动依旧能够继续工作,且不重复之前工作!

图1 网站主页面上的序贯模型url (相对路径)

API的实现

上面的爬虫运行半个小时之后,大概就会有500多条有效数据,这些数据全部被存在redis里面(hset)。
可以参见我之前的文章快速入门 基于Flask实现Restful风格API,比较详细的介绍了如何使用flask来实现一个restful的API。

这里的flask程序需要从redis拿数据,我自己定义了一个数据源(连接redis分发数据)。

澳门新濠3559 12

目前已经完成的工作

目前已经基本实现API获取数据,爬虫还正在努力的运行,稳定以后,将会设置系统任务,在每天半夜3点开始,五点结束。

看一张效果图吧:

澳门新濠3559 13

API 可以返回简洁有用的数据

澳门新濠3559 14

随便点击一个,预览图片也很不错呢

图2 序贯模型页面的真实url (绝对路径)

下一步的工作

根据这个特征,我们可以设计相对的函数,来获取所有待爬取页面的真实url。此外,为了能够对页面进行正确的保存,需要给文件进行命名,这里将所有页面名称定位info.html。例如,序贯模型的页面在本地就存储在  ./latest/getting_started/sequential_model/info.html 文件中。

继续发现和修补爬虫的bug

工作2.将页面存储到本地时,将其中的超链接地址改为目标静态页面的相对路径。例如,对于主页 ,它的序贯模型索引的url如下:

增加用户系统和认证机制,这样大家就可以收藏了

澳门新濠3559 15

租一个云主机(求有需求的伙伴打赏)

而对于我们所爬取下来的静态主页 ./latest/info.html 来说,它的序贯模型索引的url如下:

编写客户端

澳门新濠3559 16

公开源代码

github地址

最后,如果你对这个项目感兴趣,请发我简信,或者直接在下面评论!
还有,服务器好贵,真希望有人能打赏,让我早点把API公开。

我们需要精确的指向该页面在本地目录中所保存的地址。

注意:我们只修改以<li class="toctree-l1 "></li>标签进行环绕的超链接<a>,其他类似href=”#keras-cn”的链接只是JavaScript的一个位置移动操作,并不会对新的页面进行加载(这一点我花了好久时间才看懂,之前一直以为需要对 #keras-cn新建一个路径,再对其页面进行静态保存……)。

 

做完了上述工作,就可以对网页进行爬取了,但此时,爬取出的网页大概是这个样子:

澳门新濠3559 17

这是因为我们此时并没有下载网页的样式文件.css与.js文件,导致一片白板。继续观察网页源码,发现该网站下所有的页面,其.css文件与.js文件路径都在页面的<head>标签内进行规定,且均指向/lastest/css/文件夹与/latest/js/文件夹。因此我们只要在存储网站主页的时候,对.css与.js文档存储一次即可。

 

整个网站爬取的流程如下:

①使用selenium+phantomJS打开根页面,获取页面左侧索引的全部url,将其存储在url_list中。

②调用页面保存函数,对根页面进行保存。

③下载<head>标签内的 .css 与 .js 文件。

④循环遍历url_list中的页面地址,使用selenimu的webdriver进行打开,调用页面保存函数对页面内容进行保存。

 

注意事项:

1.获取索引URL时,由于href给出的是相对路径,需要将相对url拼接为绝对url再存入url_list。

2.存取网页时,根据<head>中的<meta charset="utf-8">,需要将页面使用utf-8编码进行保存。具体语法如下:

1 with open(save_path+page_name,'wb') as f_in:
2     f_in.write(driver.page_source.encode('utf-8'))

3.每爬取一个页面,暂停一段时间,这既是互联网上的礼节礼貌问题,也降低了自己被反爬措施限制的风险。

time.sleep(3)  # 勿频繁访问,以防网站封禁

 在我第一次爬取tensorflow手册时,没有设置访问延迟,被网站锁了一个星期不能访问,都是血泪教训~。

4.通过代码下载的.css和.js文件有可能不全,我通过右键网页→页面另存为,获取了完整的js和css文件,将其移动到对应的/latest/css/和/latest/js/路径下即可。

 

具体实现:

①获取绝对url函数:

 1 def get_abs_url(url,href):     
 2     if '../' in href:
 3         count = 0
 4         while('../' in href):
 5             count += 1
 6             href = href[3:]
 7         for i in range(count):
 8             if url[-1]=='/':     # 去除掉url最后一个 '/'
 9                 url = url[:-1]
10             rare = url.split('/')[-1]
11             url = url.split(rare)[0]
12         if href[-1]=='/':
13             return url+href[:-1]
14         else:
15             return url+href
16     elif './' in href:             
17         href = href[2:]

使用该函数,对不同类型的相对路径进行解析,获取能正确访问对应页面的绝对url。

 

②保存数据函数(主要用于保存css文件和js文件)

 1 def save_data(driver, path):   # 这个path是指/latest/路径之后的path。 页面的话要加上  路径/info.html
 2     if path[-4:]=='.ico':
 3         with open('./latest/'+path,'wb') as f_in:
 4             f_in.write(driver.page_source)
 5     elif path[-4:]=='.css' or path[-3:]=='.js':
 6         with open('./latest/'+path,'wb') as f_in:
 7             f_in.write(driver.page_source.encode('utf-8'))
 8     else:
 9         with open('./latest/'+path+'/info.html','wb') as f_in:
10             f_in.write(driver.page_source.encode('utf-8'))

 

③保存页面函数,根据路径和页面内容,来对页面进行保存。并且对页面中的url地址进行修改,以便正确的调用静态页面。

 1 def save_page(driver,save_path):
 2     with open(save_path+page_name,'wb') as f_in:
 3         f_in.write(driver.page_source.encode('utf-8'))
 4     temp_file_lines = []
 5     # 下面这一步把页面中的 'layers/pooling_layer/' 改为 './layers/pooling_layer/info.html'  以方便静态调用
 6     with open(save_path+page_name,'r', encoding="utf-8") as f_in:   
 7         f_lines = f_in.readlines()
 8         for i in range(len(f_lines)):
 9             if 'toctree-l1' in f_lines[i] and "href="."" not in f_lines[i+1]:
10                 temp_loc = f_lines[i+1].split('"')[3]
11                 new_loc = './'+temp_loc+page_name
12                 f_lines[i+1] = f_lines[i+1].split(temp_loc)[0] + new_loc + f_lines[i+1].split(temp_loc)[1]
13             temp_file_lines.append(f_lines[i].encode('utf-8'))  
14     with open(save_path+page_name,'wb') as f_in:
15         f_in.writelines(temp_file_lines)

 

④文件路径获取函数

1 def get_save_path(url):     # 将url变为相对的文件保存路径。
2     if url[-1]!='/':
3         url = url+'/'
4     rare = url.split(root_url)[1]
5     path = root_dir+rare
6     return path

通过该函数获取静态页面存储路径(相对路径)。

 

另外还有一些逻辑直接写在了main函数里,如通过BeautifulSoup解析url地址:

1 driver = webdriver.PhantomJS()
2 driver.get(root_url)
3 li_list = BeautifulSoup(driver.page_source,'html.parser').find_all('li',class_='toctree-l1')

通过<head>标签解析.css与.js文件地址:

 1 # TODO 在head标签中寻找 .css 及 .js
 2     link_list = BeautifulSoup(driver.page_source,'html.parser').find('head').find_all('link')
 3     script_list = BeautifulSoup(driver.page_source,'html.parser').find('head').find_all('script')
 4     css_list = []   # 存储css文件
 5     for link in link_list:
 6         href = link['href']
 7         if 'https://' in href:
 8             css_list.append(href)
 9         else:
10             css_list.append(get_abs_url(root_url,href))
11     js_list = []    # 存储 js 文件
12     for js in script_list:
13         try:
14             href = js['src']
15         except:
16             continue
17         if 'https://' in href:
18             js_list.append(href)
19         else:
20             js_list.append(get_abs_url(root_url,href))

 

 

具体的代码可从我的GitHub上进行下载。

其中的main.py便是程序代码,python3实现。

 

 

 

[1] selenium用法详解

 

 

 

编辑:编程 本文来源:为了更方便的在内网环境下快速的查阅资料,更

关键词: