maqian

一, 引入

回顾requests实现数据爬取的流程:

  1. 指定url
  2. 基于requests模块发起请求
  3. 获取响应对象中的数据
  4. 进行持久化存储

其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析。因为大多数情况下的需求,我们都会指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,而不是整个页面的数据。数据爬取的流程可以修改为:

  1. 指定url
  2. 基于requests模块发起请求
  3. 获取响应中的数据
  4. 数据解析
  5. 进行持久化存储

实现方式:

  • 正则
  • bs4
  • xpath
  • pyquery

数据解析的通用原理是什么?

  • 标签的定位
  • 数据的提取

页面中的相关的字符串的数据都存储在哪里呢?

  • 标签中间
  • 标签的属性中

二, 正则解析

常用正则表达式回顾:

单字符:
    . : 除换行以外所有字符
    [] :[aoe] [a-w] 匹配集合中任意一个字符
    \d :数字  [0-9]
    \D : 非数字
    \w :数字、字母、下划线、中文
    \W : 非\w
    \s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
    \S : 非空白
数量修饰:
    * : 任意多次  >=0
    + : 至少1次   >=1
    ? : 可有可无  0次或者1次
    {m} :固定m次 hello{3,}
    {m,} :至少m次
    {m,n} :m-n次
边界:
    $ : 以某某结尾 
    ^ : 以某某开头
分组:
	(ab)  
贪婪模式: .*
非贪婪(惰性)模式: .*?

re.I : 忽略大小写
re.M :多行匹配
re.S :单行匹配

re.sub(正则表达式, 替换内容, 字符串)

练习:

将煎蛋网中的图片数据进行爬取且存储在本地

import requests
import re
import os
from urllib import request
file_path = \'./煎蛋网/\'
if not os.path.exists(file_path):
    os.mkdir(file_path)
url = \'http://jandan.net/pic/MjAxOTEwMDktNjY=#comments\'
headers = {
    \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36\'
}
page_text = requests.get(url, headers=headers).text
ex = \'<div class="text">.*?<img src="(.*?)" referrerPolicy.*?</div>\'
src_list = re.findall(ex, page_text, re.S)
for src in src_list:
    if \'org_src\' in src:
        src = re.findall(\'org_src="(.*?)" onload\', src)[0]
    img_url = \'http:\' + src
    img_path = file_path + src.split(\'/\')[-1]
    request.urlretrieve(img_url, img_path)
    print(src.split(\'/\')[-1], \'爬取成功~~\')

三, Xpath解析

  • 环境的安装
    • pip install lxml
  • 解析原理
    • 实例化一个etree的对象,且把即将被解析的页面源码数据加载到该对象中
    • 调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
  • etree对象的实例化
    • etree.parse(\'fileName\')
    • etree.HTML(page_text)
  • 标签定位
    • 最左侧的/:一定要从根标签开始进行标签定位
    • 非最左侧的/:表示一个层级
    • 最左侧的//:可以从任意位置进行指定标签的定位
    • 非最左侧的//:表示多个层级
    • 属性定位://tagName[@attrName="value"]
    • 索引定位://tagName[@attrName="value"]/li[2],索引是从1开始
    • 逻辑运算:
      • 找到href属性值为空且class属性值为du的a标签
      • //a[@href="" and @class="du"]
    • 模糊匹配:
      • //div[contains(@class, "ng")]
      • //div[starts-with(@class, "ta")]
  • 取文本
    • /text():直系的文本内容
    • //text():所有的文本内容
  • 取属性
    • /@attrName

练习:

需求:爬取虎牙主播名称,热度和标题

from lxml import etree
url = \'https://www.huya.com/g/xingxiu\'
page_text = requests.get(url, headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath(\'//ul[@id="js-live-list"]/li\')
for li in li_list:
    title = li.xpath(\'./a[2]/text()\')[0]
    avatar = li.xpath(\'./span/span[1]/i/text()\')[0]
    hot = li.xpath(\'./span/span[2]/i[2]/text()\')[0]
    print(title, avatar, hot)

爬取http://pic.netbian.com/4kmeinv/中前五页的图片数据

  • 中文乱码的处理
  • 多页码数据的爬取
file_path = \'./妹子图/\'
if not os.path.exists(file_path):
    os.mkdir(file_path)
url = \'http://pic.netbian.com/4kmeinv/index_{}.html\'
for page in range(1, 6):
    if page == 1:
        new_url = \'http://pic.netbian.com/4kmeinv/\'
    else:
        new_url = url.format(page)
    page_text = requests.get(new_url, headers=headers).text
    tree = etree.HTML(page_text)
    li_list = tree.xpath(\'//div[@class="slist"]/ul/li\')
    for li in li_list:
        title = li.xpath(\'./a/b/text()\')[0].encode(\'iso-8859-1\').decode(\'gbk\')
        src = \'http://pic.netbian.com\' + li.xpath(\'./a/img/@src\')[0]
        img_path = file_path + title + \'.\' + src.split(\'.\')[-1]
        request.urlretrieve(src, img_path)
    print(\'第{}页爬取完毕\'.format(page))

爬取全国城市的名称

url = \'https://www.aqistudy.cn/historydata/\'
page_text = requests.get(url, headers=headers).text
# soup = BeautifulSoup(page_text, \'lxml\')
# hot_cities = soup.select(\'.hot li a\')
# other_cities = soup.select(\'.all li a\')
# cities = hot_cities + other_cities
# for city in cities:
#     print(city.text)

tree = etree.HTML(page_text)
# | 表示 or
cities = tree.xpath(\'//div[@class="hot"]//a/text() | //div[@class="all"]//a/text()\')
for city in cities:
    print(city)

四, BeautifulSoup解析

  • 环境的安装:
    • pip install bs4
    • pip install lxml
  • bs4的解析原理:
    • 实例化一个BeautifulSoup的一个对象,把即将被解析的页面源码数据加载到该对象中
    • 需要调用BeautifulSoup对象中的相关的方法和属性进行标签定位和数据的提取
  • BeautifulSoup的实例化
    • BeautifulSoup(fp,\'lxml\'):将本地存储的html文档中的页面源码数据加载到该对象中
    • BeautifulSoup(page_text,\'lxml\'):将从互联网中请求到的页面源码数据加载到该对象中
  • 标签的定位
    • soup.tagName:只可以定位到第一个tagName标签
    • 属性定位:soup.find(\'tagName\',attrName=\'value\'),只可以定位到符合要求的第一个标签
      • 特别的: class属性 class_=\'value\'
      • findAll:返回值是一个列表。可以定位到符合要求的所有标签
    • 选择器定位:soup.select(\'选择器\')
      • 选择器:id,class,tag,层级选择器(大于号表示一个层级,空格表示多个层级)
  • 取文本
    • text:将标签中所有的文本取出
    • string:将标签中直系的文本取出
  • 取属性
    • tag[\'attrName\']

练习:

需求:使用bs4解析红楼梦小说的标题和内容,存储到本地

url = \'http://www.shicimingju.com/book/hongloumeng.html\'
page_text = requests.get(url, headers=headers).text
soup = BeautifulSoup(page_text, \'lxml\')
a_list = soup.select(\'.book-mulu a\')
f1 = open(\'红楼梦.text\', \'w\', encoding=\'utf-8\')
for a in a_list:
    title = a.text
    book_url = \'http://www.shicimingju.com\' + a[\'href\']
    book_text = requests.get(book_url, headers=headers).text
    book_soup = BeautifulSoup(book_text, \'lxml\')
    book_data = book_soup.select(\'.chapter_content\')[0].text
    f1.write(title + \'\n\' + book_data + \'\n\')
    print(title, \'爬取成功~\')
f1.close()

五, pyquery解析

和jQuery高度相似,容易上手,但是效率和正确率不太好.

https://blog.csdn.net/sunt2018/article/details/85932516

分类:

技术点:

相关文章: