数据解析的方式

数据解析

- 数据解析
    - 数据解析的作用:
        - 可以帮助我们实现聚焦爬虫
    - 数据解析的实现方式:
        - 正则
        - bs4
        - xpath
        - pyquery
     - 数据解析的通用原理
         - 问题1:聚焦爬虫爬取的数据是存储在哪里的?
             - 都被存储在了相关的标签之中and相关标签的属性中
         - 1.定位标签
         - 2.取文本或者取属性

一、正则表达式解析

# 示例一:正则表达式解析数据抓取糗事百科糗图
import os
import re
from urllib import request
dirName="./qiutu"
if not os.path.exists(dirName):
    os.mkdir(dirName)
base_url="https://www.qiushibaike.com/imgrank/page/%d/"
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
}
pattern='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
for i in range(1,3):
    url=format(base_url%i)
    response=requests.get(url=url,headers=headers)
    page_text=response.text
    src_list=re.findall(pattern,page_text,re.S)
    for src in src_list:
        src="https:"+src
        img_name=src.split("/")[-1]
        img_path=dirName+"/"+img_name
        request.urlretrieve(src,filename=img_path)
        print(img_name+"下载完成...")

二、bs4数据解析

原理分析:

- bs4解析
    - bs4解析的原理:
        - 实例化一个BeautifulSoup的对象,需要将即将被解析的页面源码数据加载到该对象中
        - 调用BeautifulSoup对象中的相关方法和属性进行标签定位和数据提取
    - 环境的安装:
        - pip install bs4
        - pip install lxml
    - BeautifulSoup的实例化:
        - BeautifulSoup(fp,'lxml'):将本地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中
        - BeautifulSoup(page_text,'lxml'):将从互联网上获取的页面源码数据加载到实例化好的BeautifulSoup对象中

使用方式:

- 定位标签的操作:
    - soup.tagName:定位到第一个出现的tagName标签
    - 属性定位:soup.find('tagName',attrName='value')
    - 属性定位:soup.find_all('tagName',attrName='value'),返回值为列表
    - 选择器定位:soup.select('选择器')
        - 层级选择器:>表示一个层级  空格表示多个层级
- 取文本
    - .string:获取直系的文本内容
    - .text:获取所有的文本内容
- 取属性
    - tagName['attrName']

使用方法示例:

from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
soup.div
soup.find('div',class_='song')
soup.find('a',id="feng")
soup.find_all('div',class_="song")
soup.select('#feng')
soup.select('.tang > ul > li')
soup.select('.tang li') #
a_tag = soup.select('#feng')[0]
a_tag.text
div = soup.div
div.string
div = soup.find('div',class_="song")
div.string
a_tag = soup.select('#feng')[0]
a_tag['href']

示例:

# 示例二:使用bs4 数据解析下载三国演义
import lxml
from bs4 import BeautifulSoup
fp=open("sanguo.txt",'a',encoding="utf-8")
url="http://www.shicimingju.com/book/sanguoyanyi.html"
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
}
response=requests.get(url=url,headers=headers)
page_text=response.text
soup=BeautifulSoup(page_text,"lxml")
li_list=soup.select(".book-mulu li a")
for i in li_list:
    chapter=i.string
    detail_src="http://www.shicimingju.com"+i["href"]
    response2=requests.get(url=detail_src,headers=headers)
    detail_text=response2.text
    soup2=BeautifulSoup(detail_text,"lxml")
    content=soup2.find("div",class_="chapter_content").text
    fp.write(chapter+"\n"+content+"\n")
    print(chapter,"下载完毕...")
fp.close()

三、xpath数据解析

原理分析:

- xpath解析
    - xpath解析的实现原理
        - 1.实例化一个etree的对象,然后将即将被解析的页面源码加载到改对象中
        - 2.使用etree对象中的xpath方法结合着不同形式的xpath表达式实现标签定位和数据提取
    - 环境安装:
        - pip install lxml
    - etree对象的实例化:
        - etree.parse('test.html')
        - etree.HTML(page_text)

使用方式:

- xpath表达式:xpath方法的返回值一定是一个列表
    - 最左侧的/表示:xpath表达式一定要从根标签逐层进行标签查找和定位
    - 最左侧的//表示:xpath表达式可以从任意位置定位标签
    - 非最左侧的/:表示一个层级
    - 非最左侧的//:表示夸多个层级
    - 属性定位://tagName[@attrName="value"]
    - 索引定位://tagName[index] 索引是从1开始
- 取文本:
    - /text():直系文本内容
    - //text():所有的文本内容
- 取属性:
    - /@attrName

使用方式示例:

from lxml import etree
tree = etree.parse('./test.html')
tree.xpath('/html/head/title')
tree.xpath('//title')
tree.xpath('/html/body//p')
tree.xpath('//p')
tree.xpath('//div[@class="song"]')
tree.xpath('//li[7]')
tree.xpath('//a[@id="feng"]/text()')[0]
tree.xpath('//div[@class="song"]//text()')
tree.xpath('//a[@id="feng"]/@href')

实战3.1

# 示例3.1:使用xpath解析数据获取糗事百科段子及作者
from lxml import etree
base_url="https://www.qiushibaike.com/text/page/1/"
response=requests.get(url,headers=headers)
tree=etree.HTML(response.text)
item_list=tree.xpath('//div[@class="col1 old-style-col1"]/div')
for i in item_list:
    author=i.xpath('.//a[2]/h2/text()')[0]
    content=i.xpath('.//div[@class="content"]/span//text()')[0]
    print(author,content)
    print("------"*20)
#     tree.xpath(//div[@class="article"]//div[@class="content"]/span/text())

实战3.2

# 示例3.2:http://pic.netbian.com/4kmeinv/中文乱码的处理  没有分页下载
dirName="./meinv"
if not os.path.exists(dirName):
    os.mkdir(dirName)
url="http://pic.netbian.com/4kmeinv/"
response_text=requests.get(url,headers=headers).text
tree=etree.HTML(response_text)
a_list=tree.xpath('//div[@class="slist"]/ul[@class="clearfix"]/li/a')
for i in a_list:
    img_title=i.xpath('./b/text()')[0]
    img_title=img_title.encode("iso-8859-1").decode("gbk")
    img_src="http://pic.netbian.com"+i.xpath('./img/@src')[0]
    img_path=dirName+"/"+img_title+".jpg"
    img_data=requests.get(img_src,headers=headers).content
    with open(img_path,"wb") as fp:
        fp.write(img_data)
        print(img_title,"下载完成...")

实战3.3

# 示例3.2:http://pic.netbian.com/4kmeinv/中文乱码的处理  有分页下载
dirName="./meinvPage"
if not os.path.exists(dirName):
    os.mkdir(dirName)

for index in range(1,4):
    print("正在下载第%s页..."%str(index))
    if index==1:
        url="http://pic.netbian.com/4kmeinv/"
    else:
        url=format("http://pic.netbian.com/4kmeinv/index_%d.html"%index)
    response_text=requests.get(url,headers=headers).text
    tree=etree.HTML(response_text)
    a_list=tree.xpath('//div[@class="slist"]/ul[@class="clearfix"]/li/a')
    for i in a_list:
        img_title=i.xpath('./b/text()')[0]
        img_title=img_title.encode("iso-8859-1").decode("gbk")
        img_src="http://pic.netbian.com"+i.xpath('./img/@src')[0]
        img_path=dirName+"/"+img_title+".jpg"
        img_data=requests.get(img_src,headers=headers).content
        with open(img_path,"wb") as fp:
            fp.write(img_data)
            print(img_title,"下载完成...")

实战3.4

#https://www.aqistudy.cn/historydata/  抓取所有城市名称
url="https://www.aqistudy.cn/historydata/"
response_text=requests.get(url,headers=headers).text
tree=etree.HTML(response_text)
#方式一
# hot_cities=tree.xpath('//div[@class="hot"]//li/a/text()')
# all_cities=tree.xpath('//div[@class="all"]//li/a/text()')
# print(hot_cities)
# print(all_cities)
#方式二
cities=tree.xpath('//div[@class="hot"]//li/a/text() | //div[@class="all"]//li/a/text()')
print(cities)

 

持久化数据的两种方式

1:使用requests方式持久化数据

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
}
#如何爬取图片
url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg'
img_data = requests.get(url,headers=headers).content #byte类型数据
with open('./img.jpg','wb') as fp:
    fp.write(img_data)

2:使用urllib方式持久化数据

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
}
#弊端:不能使用UA伪装
from urllib import request
url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg'
request.urlretrieve(url,filename='./qiutu.jpg')

 

 

总结

不管使用哪种数据解析方式,第一步都需要使用requests将整个页面数据拿到,然后再根据不同的数据解析方式使用不同的方法进行提取需要的数据部分。

 

posted @ 2020-05-05 12:25  佛祖让我来巡山  阅读(309)  评论(0编辑  收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网