Requests HTML 是原 Requests 库的作者设计的,主要是为了易用性,作者集成了很多 好用的特性,比如 PyQuery 库,Requests 库,以前这些库都是对存在的,解析 HTML 的方法 也相对分散,本次作者经过良好的设计,使得 HTML 解析可以统一到一个库里面,并且作者还集成 了 JS 渲染功能,该功能一直是缺失的,而且很难处理,以前都是通过解析 JSON 数据来抓取数据 的,如今作者提供了一个思路,通过 chrome 内核来渲染 JS 文件得到最终完整的 HTML。

requests-html 的基本特性如下:

  • JS 渲染功能
  • Requests 集成
  • JQuery like selector
  • Xpath support
  • connection pool

整体来讲,这个库还是非常棒的,用过了就爱不释手。当然这个库也不是完美的,目前只能在 Python 3.6 环境下运行,并且这个库属于早期发展阶段,很多API并不完善,需要进一步丰富API。

下面以抓取百度的花椒直播答题题库为例子来使用 Requests HTML 这个库。可以先看下这个链接: https://zhidao.baidu.com/culture/topic?name=huajiao

首先需要的是解析各个场次的 URL,然后才是解析该场次的题目,答案,分析。具体的需要分析 HTML 结构, 线上代码,然后在做部分分析:

# -*- coding: utf-8 -*-

"""

    use requests html parse html
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Fetures:
        - JQuery like way
        - Request lib
        - XPath support
        - JS Render Support

"""
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed

from requests_html import HTMLSession


def crawl_baidu_qa(url):
    """

    Crawl only one contest

    :param url:
    :return:
    """

    session = HTMLSession()
    resp = session.get(url)

    question_li = resp.html.find(".text-content p")

    start = True
    answers = []
    for index, element in enumerate(question_li):

        if not element.text:
            if index + 3 < len(question_li):
                start = True
                continue
            else:
                break

        if not start:
            continue

        answers.append({
            "question": element.text.split(".")[-1],
            "answers": question_li[index + 1].text.split("\xa0\xa0\xa0"),
            "select": question_li[index + 2].text.split(":")[-1],
            "analyze": question_li[index + 3].text.split(":")[-1]
        })
        start = False

    return answers


def main():
    """
    crawl all answers

    :return:
    """
    session = HTMLSession()
    resp = session.get("https://zhidao.baidu.com/culture/topic?name=huajiao")
    urls = map(lambda e: e.attrs["href"], resp.html.find(".item-content a"))
    qa_li = []
    with ThreadPoolExecutor(10) as executor:
        futures = {
            url: executor.submit(crawl_baidu_qa, url)
            for url in urls
        }
        for future in as_completed(futures.values()):
            qa_li.extend(future.result())
    print(qa_li)


if __name__ == "__main__":
    main()

如上代码中,在 main 函数中,我们先解析出来各个场次的 URL,然后再解析出 URL 中的内容。两次 解析中我使用的都是 JQuery 的 selector ,这个很好用,而且是通用的,由于页面的题目,答案,分析, 并不是很好的处理,所以还是需要花点思考。

未完待续…