Python爬虫工具Requests-HTML

  • A+
所属分类:Python库介绍
摘要这一篇文章主要介绍python爬虫的一些内容. 主要是关于requests-html使用的一些记录。其中会包含一些css selector和xpath的内容.

Request构造请求参数

这里介绍一个例子,进行url的构造后进行请求(常用语请求一些api的接口,如历史天气)。这里会使用Request进行完成。

  1. #coding:utf-8
  2. import json,urllib
  3. try:
  4.     from urllib.parse import urlencode
  5. except ImportError:
  6.     from urllib import urlencode
  7. #from urllib.request import urlopen
  8. import requests
  9. def get_message(find_date):
  10.   url = 'http://api.k780.com'
  11.   params = {
  12.     'app' : 'weather.history',
  13.     'weaid' : '1',#城市id
  14.     'date' : find_date,#查询日期
  15.     'appkey' : '33690',
  16.     'sign' : 'bdcf684483992488f5d296a53b846283',
  17.     'format' : 'json',
  18.   }
  19.   params = urlencode(params)
  20.   try:
  21.       f = requests.get('%s?%s' % (url, params))
  22.       while f.status_code != 200: # 重复请求
  23.           f = requests.get('%s?%s' % (url, params))
  24.       html=f.content # 获取请求内容
  25.       nowapi_call=str(html)
  26.       a_result = json.loads(nowapi_call)
  27.   return a_result

上面的代码作为一个小的样例,可以在params中定制自己需要的参数。

Requests-HTML的使用

加上header和使用代理

有的时候我们需要模拟浏览器的结果, 所以我们需要加上header. 有的时候我又需要使用代理. 这两个功能在request-HTML都是很方便的进行实现的.

  1. session = HTMLSession()
  2. proxie = {
  3.     'http': 'http://127.0.0.1:1080',
  4. }
  5. headers = {
  6.     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
  7.     # 'Cookie': '__cfduid=d38a3b9c5846e5db96ef23a5eb78642e91530061695'
  8. }
  9. # 进行爬取
  10. r = session.get(url,proxies=proxie,headers=headers)

数据提取CSS Selector

我们使用百度首页做一个例子,我们想要获得value中的值, 我们分别可以使用下面两种方式。

Python爬虫工具Requests-HTML
  1. from requests_html import HTMLSession
  2. session = HTMLSession()
  3. url = 'https://www.baidu.com/'
  4. r = session.get(url)

根据ID进行提取

  1. # 通过ID的方式搜索
  2. for i in r.html.find('span input#su'):
  3.     print(i.lxml.xpath('//@value'))
Python爬虫工具Requests-HTML

我们可以看到上面id为su的input,被span包裹,所以提取的时候写法为:span input#su.

根据class进行提取

  1. # 通过class的方式搜索
  2. for i in r.html.find('span input.s_btn'):
  3.     print(i.lxml.xpath('//@value'))
Python爬虫工具Requests-HTML

通过class进行提取的时候,使用.的记号进行提取,如这里的input的class是s_btn,就可以写成input.s_btn来进行提取。

数据提取Xpath

XPath 是一门路径提取语言,常用于从 html/xml 文件中提取信息。它的基规则如下

Python爬虫工具Requests-HTML

我们在上面的提取中,为了提取input中value属性的值,就已经使用了xpath了,具体可以看重新看一下上面的例子。

一个Requests-HTML的例子

上面只是简单讲了一下Request-HTML的用法, 下面看一个具体的例子. 也是看一下爬虫通常会有哪些步骤, 一个好的代码(比较规范)会写成什么样子的.

下面的一个例子是获取网站上每一页图片的例子, 主要的步骤如下所示:

  • 读取想要爬取的网页的url
  • 获得所有的页面(如果可以, 一下获得所有的连接, 不要每次判断是否翻页)
  • 获取每一页图片的链接
  • 图片的下载

创建session, 进行初始化

导入需要的库.

  1. from requests_html import HTMLSession
  2. from multiprocessing import Pool
  3. import osthreadingtime
  4. import random

接着我们创建session, 并定义header和proxy.

  1. session = HTMLSession()
  2. proxie = {
  3.     'http': 'http://127.0.0.1:1080',
  4. }
  5. headers = {
  6.     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
  7.     # 'Cookie': '__cfduid=d38a3b9c5846e5db96ef23a5eb78642e91530061695'
  8. }

 获取需要爬取的链接

有的时候, 我们会将我们需要爬取的链接写入文本, 这样可以方便我们进行修改. 我们可以使用下面的方式进行读取.

  1. # --------------
  2. # 读取文件中的url
  3. # --------------
  4. def duqu():
  5.     with open('list.txt', 'r') as f:
  6.         url_list = f.readlines()
  7.     return url_list

获取所有的链接

我们一次把获取要爬取的所有页面的链接(如果可以的话), 后面就不用进行翻页的判断了.

  1. # --------------------
  2. # 获得漫画所有页面的链接
  3. # --------------------
  4. def get_page_list(url):
  5.     print('开始获取漫画分页列表')
  6.     firstPage = session.get(url,proxies=proxie)
  7.     container = firstPage.html.find('.entry-content .page-links', first=True).links
  8.     title = firstPage.html.find('header h1.entry-title', first=True).text
  9.     num = len(container) # 漫画链接的数量
  10.     link_list = [url+'/'+str(x) for x in range(1,num+2)] # 生成所有需要的链接
  11.     print("漫画链接: \n{}".format(link_list))
  12.     print("漫画标题: \n{}".format(title))
  13.     print('获取漫画分页列表完成')
  14.     return title,link_list

 获得图片链接

上面我们获取了每一页的链接, 下面我们获取每一页图片的链接, 我们暂时只把图片的链接保存下来, 先不对图片进行保存, 保存在后面进行操作.

  1. # ----------------
  2. # 获得图片所有的链接
  3. # ----------------
  4. def get_img_list(page_list):
  5.     """
  6.     按顺序获得每一页的所有图片链接
  7.     """
  8.     img_list = []
  9.     for page in page_list:
  10.         r = session.get(page,proxies=proxie)
  11.         time.sleep(random.random()*5) # 每次获得图片的时候停顿一下, 不要跑太快了
  12.         single_page_list = r.html.find('.entry-content div.single-content p')
  13.         img_list += [img.find('p img')[1].attrs['src'] for img in single_page_list]
  14.     # print(img_list)
  15.     print('获取图片列表完成')
  16.     return img_list

图片的保存

有了图片的链接之后就是进行图片的保存了, 我们加入了一个文件夹是否存在的判断. 这里图片的保存我们使用多线程来进行操作.

  1. # ---------
  2. # 图片的保存
  3. # ---------
  4. def mkdir(path):
  5.     # 引入模块
  6.     import os
  7.     # 去除首位空格
  8.     path=path.strip()
  9.     # 去除尾部 \ 符号
  10.     path=path.rstrip("\\")
  11.     # 判断路径是否存在
  12.     # 存在     True
  13.     # 不存在   False
  14.     isExists=os.path.exists(path)
  15.     # 判断结果
  16.     if not isExists:
  17.         # 如果不存在则创建目录
  18.         # 创建目录操作函数
  19.         os.makedirs(path)
  20.         print(path+' 创建成功')
  21.         return True
  22.     else:
  23.         # 如果目录存在则不创建,并提示目录已存在
  24.         print(path+' 目录已存在')
  25.         return False
  26. def saver(mkpath, img_url, n ,total):
  27.     """
  28.     mkpath: 图片保存的文件夹
  29.     img_url: 要保存的图片的url
  30.     n: 要保持的图片的编号
  31.     total: 所有的图片的数量
  32.     """
  33.     img_url = img_url.strip()
  34.     res = session.get(img_url,proxies=proxie,headers=headers)
  35.     # print(res.content)
  36.     with open(mkpath + '\\%03d.jpg' % n,'wb') as f:
  37.         f.write(res.content)
  38.     print('第%03d张图片下载完成/共%03d张图片' % (n,total))
  39. def save(img_urls,title):
  40.     n = 1
  41.     mkpath = './comic/' + title # 漫画保存的路径
  42.     total = len(img_urls)
  43.     mkdir(mkpath) # 如果没有对应文件夹就进行创建
  44.     for img_url in img_urls:
  45.         t = threading.Thread(target=saver,args=(mkpath,img_url,n,total))
  46.         t.start()
  47.         t.join()
  48.         n += 1

主程序

把上面所有需要的东西都定义好之后, 我们把他们按顺序组合起来. 这样写方便后面使用多进程.

  1. # -------
  2. # 主程序
  3. # ------
  4. def run(url):
  5.     title,page_list = get_page_list(url)
  6.     imgurls = get_img_list(page_list)
  7.     save(imgurls,title)

开始爬取

最后一步就是开始爬取了, 我们在这里使用了多进程的方式, 可以同时爬取多个链接.

  1. if __name__ == '__main__':
  2.     url_list = duqu()
  3.     p = Pool(2)
  4.     print('begin')
  5.     for url in url_list:
  6.         url = url.strip()
  7.         p.apply_async(run,args=(url,))
  8.     p.close()
  9.     p.join()
  10.     print('All finished!!!')

 

参考链接

Python爬虫工具Requests-HTML
  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: