欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

05 Python网络爬虫的数据解析方式

程序员文章站 2022-04-14 18:48:01
一.爬虫数据解析的流程 1.指定url 2.基于requests模块发起请求 3.获取响应中的数据 4.数据解析 5.进行持久化存储 二.解析方法 (1)正则解析 (2)bs4解析 (3)xpath解析 1. 正则解析 常用正则表达式 正则使用练习: 应用: 爬取糗事百科指定页面的糗图,并将其保存到 ......

一.爬虫数据解析的流程

  1.指定url

  2.基于requests模块发起请求

  3.获取响应中的数据

  4.数据解析

  5.进行持久化存储

二.解析方法

  (1)正则解析

  (2)bs4解析

  (3)xpath解析

  1. 正则解析

    常用正则表达式

  

 1 单字符:
 2         . : 除换行以外所有字符
 3         [] :[aoe] [a-w] 匹配集合中任意一个字符
 4         \d :数字  [0-9]
 5         \d : 非数字
 6         \w :数字、字母、下划线、中文
 7         \w : 非\w
 8         \s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
 9         \s : 非空白
10 数量修饰:
11         * : 任意多次  >=0
12         + : 至少1次   >=1
13         ? : 可有可无  0次或者1次
14         {m} :固定m次 hello{3,}
15         {m,} :至少m次
16         {m,n} :m-n次
17 边界:
18         $ : 以某某结尾 
19         ^ : 以某某开头
20 分组:
21         (ab)  
22 贪婪模式: .*
23 非贪婪(惰性)模式: .*?
24 
25     re.i : 忽略大小写
26     re.m :多行匹配
27     re.s :单行匹配
28 
29     re.sub(正则表达式, 替换内容, 字符串)

    正则使用练习:

 1 import re
 2 #提取出python
 3 key="javapythonc++php"
 4 re.findall('python',key)[0]
 5 #####################################################################
 6 #提取出hello world
 7 key="<html><h1>hello world<h1></html>"
 8 re.findall('<h1>(.*)<h1>',key)[0]
 9 #####################################################################
10 #提取170
11 string = '我喜欢身高为170的女孩'
12 re.findall('\d+',string)
13 #####################################################################
14 #提取出http://和https://
15 key='http://www.baidu.com and https://boob.com'
16 re.findall('https?://',key)
17 #####################################################################
18 #提取出hello
19 key='lalala<html>hello</html>hahah' #输出<html>hello</html>
20 re.findall('<[hh][tt][mm][ll]>(.*)</[hh][tt][mm][ll]>',key)
21 #####################################################################
22 #提取出hit. 
23 key='bobo@hit.edu.com'#想要匹配到hit.
24 re.findall('h.*?\.',key)
25 #####################################################################
26 #匹配sas和saas
27 key='saas and sas and saaas'
28 re.findall('sa{1,2}s',key)
29 #####################################################################
30 #匹配出i开头的行
31 string = '''fall in love with you
32 i love you very much
33 i love she
34 i love her'''
35 
36 re.findall('^.*',string,re.m)
37 #####################################################################
38 #匹配全部行
39 string1 = """<div>静夜思
40 窗前明月光
41 疑是地上霜
42 举头望明月
43 低头思故乡
44 </div>"""
45 
46 re.findall('.*',string1,re.s)

    应用:  爬取糗事百科指定页面的糗图,并将其保存到指定文件夹中

 1 import requests
 2 import re
 3 import os
 4 if __name__ == "__main__":
 5      url = 'https://www.qiushibaike.com/pic/%s/'
 6      headers={
 7          'user-agent': 'mozilla/5.0 (macintosh; intel mac os x 10_12_0) applewebkit/537.36 (khtml, like gecko) chrome/69.0.3497.100 safari/537.36',
 8      }
 9      #指定起始也结束页码
10      page_start = int(input('enter start page:'))
11      page_end = int(input('enter end page:'))
12 
13      #创建文件夹
14      if not os.path.exists('images'):
15          os.mkdir('images')
16      #循环解析且下载指定页码中的图片数据
17      for page in range(page_start,page_end+1):
18          print('正在下载第%d页图片'%page)
19          new_url = format(url % page)
20          response = requests.get(url=new_url,headers=headers)
21 
22          #解析response中的图片链接
23          e = '<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>'
24          pa = re.compile(e,re.s)
25          image_urls = pa.findall(response.text)
26           #循环下载该页码下所有的图片数据
27          for image_url in image_urls:
28              image_url = 'https:' + image_url
29              image_name = image_url.split('/')[-1]
30              image_path = 'images/'+image_name
31 
32              image_data = requests.get(url=image_url,headers=headers).content
33              with open(image_path,'wb') as fp:
34                  fp.write(image_data)

   2.beautifulsoup 解析

    需要安装:pip install bs4 bs4

    需要一个第三方库: pip install lxml

  使用方法

 1 使用流程:       
 2     - 导包:from bs4 import beautifulsoup
 3     - 使用方式:可以将一个html文档,转化为beautifulsoup对象,然后通过对象的方法或者属性去查找指定的节点内容
 4         (1)转化本地文件:
 5              - soup = beautifulsoup(open('本地文件'), 'lxml')
 6         (2)转化网络文件:
 7              - soup = beautifulsoup('字符串类型或者字节类型', 'lxml')
 8         (3)打印soup对象显示内容为html文件中的内容
 9 
10 基础巩固:
11     (1)根据标签名查找
12         - soup.a   只能找到第一个符合要求的标签
13     (2)获取属性
14         - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
15         - soup.a.attrs['href']   获取href属性
16         - soup.a['href']   也可简写为这种形式
17     (3)获取内容
18         - soup.a.string
19         - soup.a.text
20         - soup.a.get_text()
21        【注意】如果标签还有标签,那么string获取到的结果为none,而其它两个,可以获取文本内容
22     (4)find:找到第一个符合要求的标签
23         - soup.find('a')  找到第一个符合要求的
24         - soup.find('a', title="xxx")
25         - soup.find('a', alt="xxx")
26         - soup.find('a', class_="xxx")
27         - soup.find('a', id="xxx")
28     (5)find_all:找到所有符合要求的标签
29         - soup.find_all('a')
30         - soup.find_all(['a','b']) 找到所有的a和b标签
31         - soup.find_all('a', limit=2)  限制前两个
32     (6)根据选择器选择指定的内容
33                select:soup.select('#feng')
34         - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
35             - 层级选择器:
36                 div .dudu #lala .meme .xixi  下面好多级
37                 div > p > a > .lala          只能是下面一级
38         【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

  应用: 使用bs4实现将诗词名句网站中三国演义小说的每一章的内容爬去到本地磁盘进行存储   http://www.shicimingju.com/book/sanguoyanyi.html

 1 import requests
 2 from bs4 import beautifulsoup
 3 
 4 headers={
 5          'user-agent': 'mozilla/5.0 (macintosh; intel mac os x 10_12_0) applewebkit/537.36 (khtml, like gecko) chrome/69.0.3497.100 safari/537.36',
 6      }
 7 def parse_content(url):
 8     #获取标题正文页数据
 9     page_text = requests.get(url,headers=headers).text
10     soup = beautifulsoup(page_text,'lxml')
11     #解析获得标签
12     ele = soup.find('div',class_='chapter_content')
13     content = ele.text #获取标签中的数据值
14     return content
15 
16 if __name__ == "__main__":
17      url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
18      reponse = requests.get(url=url,headers=headers)
19      page_text = reponse.text
20 
21      #创建soup对象
22      soup = beautifulsoup(page_text,'lxml')
23      #解析数据
24      a_eles = soup.select('.book-mulu > ul > li > a')
25      print(a_eles)
26      cap = 1
27      for ele in a_eles:
28          print('开始下载第%d章节'%cap)
29          cap+=1
30          title = ele.string
31          content_url = 'http://www.shicimingju.com'+ele['href']
32          content = parse_content(content_url)
33 
34          with open('./sanguo.txt','w') as fp:
35              fp.write(title+":"+content+'\n\n\n\n\n')
36              print('结束下载第%d章节'%cap)

  3. xpath解析

    pip install lxml

    使用方法:

1.下载:pip install lxml
2.导包:from lxml import etree

3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点

  2.1 本地文件:tree = etree.parse(文件名)
                tree.xpath("xpath表达式")

  2.2 网络数据:tree = etree.html(网页内容字符串)
                tree.xpath("xpath表达式")

  测试数据:

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>测试bs4</title>
</head>
<body>
    <div>
        <p>百里守约</p>
    </div>
    <div class="song">
        <p>李清照</p>
        <p>王安石</p>
        <p>苏轼</p>
        <p>柳宗元</p>
        <a href="http://www.song.com/" title="赵匡胤" target="_self">
            <span>this is span</span>
        宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
        <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
        <img src="http://www.baidu.com/meinv.jpg" alt="" />
    </div>
    <div class="tang">
        <ul>
            <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
            <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
            <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
            <li><a href="http://www.sina.com" class="du">杜甫</a></li>
            <li><a href="http://www.dudu.com" class="du">杜牧</a></li>
            <li><b>杜小月</b></li>
            <li><i>度蜜月</i></li>
            <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
        </ul>
    </div>
</body>
</html>

  表达式:

 1 属性定位:
 2     #找到class属性值为song的div标签
 3     //div[@class="song"] 
 4 层级&索引定位:
 5     #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
 6     //div[@class="tang"]/ul/li[2]/a
 7 逻辑运算:
 8     #找到href属性值为空且class属性值为du的a标签
 9     //a[@href="" and @class="du"]
10 模糊匹配:
11     //div[contains(@class, "ng")]
12     //div[starts-with(@class, "ta")]
13 取文本:
14     # /表示获取某个标签下的文本内容
15     # //表示获取某个标签下的文本内容和所有子标签下的文本内容
16     //div[@class="song"]/p[1]/text()
17     //div[@class="tang"]//text()
18 取属性:
19     //div[@class="tang"]//li[2]/a/@href

  应用: 获取好段子中段子的内容和作者   http://www.haoduanzi.com

 1 from lxml import etree
 2 import requests
 3 
 4 url='http://www.haoduanzi.com/category-10_2.html'
 5 headers = {
 6         'user-agent': 'mozilla/5.0 (windows nt 6.1; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/66.0.3359.181 safari/537.36',
 7     }
 8 url_content=requests.get(url,headers=headers).text
 9 #使用xpath对url_conten进行解析
10 #使用xpath解析从网络上获取的数据
11 tree=etree.html(url_content)
12 #解析获取当页所有段子的标题
13 title_list=tree.xpath('//div[@class="log cate10 auth1"]/h3/a/text()')
14 
15 ele_div_list=tree.xpath('//div[@class="log cate10 auth1"]')
16 
17 text_list=[] #最终会存储12个段子的文本内容
18 for ele in ele_div_list:
19     #段子的文本内容(是存放在list列表中)
20     text_list=ele.xpath('./div[@class="cont"]//text()')
21     #list列表中的文本内容全部提取到一个字符串中
22     text_str=str(text_list)
23     #字符串形式的文本内容防止到all_text列表中
24     text_list.append(text_str)
25 print(title_list)
26 print(text_list)

  下载煎蛋网中的图片数据 : 

 1 import requests
 2 from lxml import etree
 3 from fake_useragent import useragent
 4 import base64
 5 import urllib.request
 6 url = 'http://jandan.net/ooxx'
 7 ua = useragent(verify_ssl=false,use_cache_server=false).random
 8 headers = {
 9     'user-agent':ua
10 }
11 page_text = requests.get(url=url,headers=headers).text
12 
13 #查看页面源码:发现所有图片的src值都是一样的。
14 #简单观察会发现每张图片加载都是通过jandan_load_img(this)这个js函数实现的。
15 #在该函数后面还有一个class值为img-hash的标签,里面存储的是一组hash值,该值就是加密后的img地址
16 #加密就是通过js函数实现的,所以分析js函数,获知加密方式,然后进行解密。
17 #通过抓包工具抓取起始url的数据包,在数据包中全局搜索js函数名(jandan_load_img),然后分析该函数实现加密的方式。
18 #在该js函数中发现有一个方法调用,该方法就是加密方式,对该方法进行搜索
19 #搜索到的方法中会发现base64和md5等字样,md5是不可逆的所以优先考虑使用base64解密
20 #print(page_text)
21 
22 tree = etree.html(page_text)
23 #在抓包工具的数据包响应对象对应的页面中进行xpath的编写,而不是在浏览器页面中。
24 #获取了加密的图片url数据
25 imgcode_list = tree.xpath('//span[@class="img-hash"]/text()')
26 imgurl_list = []
27 for url in imgcode_list:
28     #base64.b64decode(url)为byte类型,需要转成str
29     img_url = 'http:'+base64.b64decode(url).decode()
30     imgurl_list.append(img_url)
31 
32 for url in imgurl_list:
33     filepath = url.split('/')[-1]
34     urllib.request.urlretrieve(url=url,filename=filepath)
35     print(filepath+'下载成功')

 

文章: