爬虫之四种数据解析

在获取到响应数据后,需要针对性的提取其中有用的部分,这也是采集数据最常见的方式聚焦网络爬虫。

数据解析四种方式:

    1.正则表达式解析

  2.xpath解析

  3.bs4解析

  4.pyquery解析

1.正则表达式解析(re模块

  案例:爬取糗事百科---糗图:https://www.qiushibaike.com/pic/

 1 '''
 2 <div class="article block untagged mb15" id="qiushi_tag_122080461">
 3
 4 <div class="author clearfix">
 5 <a href="/users/42609417/" target="_blank" rel="nofollow">
 6 <img src="//pic.qiushibaike.com/system/avtnew/4260/42609417/medium/20190802105831.jpg" alt="灿烂的你">
 7 </a>
 8 <a href="/users/42609417/" target="_blank" title="灿烂的你">
 9 <h2>灿烂的你</h2>
10 </a>
11 <div class="articleGender womenIcon">0</div>
12 </div>
13
14
15
16 <a href="/article/122080461" target="_blank" class="contentHerf">
17 <div class="content">
18
19
20
21 <span>求大神把中间图片p掉看看长啥样</span>
22
23
24 </div>
25 </a>
26
27
28
29
30 <div class="thumb">
31
32 <a href="/article/122080461" target="_blank">
33 <img src="//pic.qiushibaike.com/system/pictures/12208/122080461/medium/3N2UVCLSJEHGAUAZ.jpg" alt="求大神把中间图片p掉看看长啥样">
34 </a>
35
36 </div>
37
38
39
40 <div class="stats">
41 <span class="stats-vote"><i class="number">33</i> 好笑</span>
42 <span class="stats-comments">
43
44
45
46
47 </span>
48 </div>
49 <div id="qiushi_counts_122080461" class="stats-buttons bar clearfix">
50 <ul class="clearfix">
51 <li id="vote-up-122080461" class="up">
52 <a href="javascript:voting(122080461,1)" class="voting" data-article="122080461" id="up-122080461" rel="nofollow">
53 <i></i>
54 <span class="number hidden">33</span>
55 </a>
56 </li>
57 <li id="vote-dn-122080461" class="down">
58 <a href="javascript:voting(122080461,-1)" class="voting" data-article="122080461" id="dn-122080461" rel="nofollow">
59 <i></i>
60 <span class="number hidden">0</span>
61 </a>
62 </li>
63
64 <li class="comments">
65 <a href="/article/122080461" id="c-122080461" class="qiushi_comments" target="_blank">
66 <i></i>
67 </a>
68 </li>
69
70 </ul>
71 </div>
72 <div class="single-share">
73 <a class="share-wechat" data-type="wechat" title="分享到微信" rel="nofollow">微信</a>
74 <a class="share-qq" data-type="qq" title="分享到QQ" rel="nofollow">QQ</a>
75 <a class="share-qzone" data-type="qzone" title="分享到QQ空间" rel="nofollow">QQ空间</a>
76 <a class="share-weibo" data-type="weibo" title="分享到微博" rel="nofollow">微博</a>
77 </div>
78 <div class="single-clear"></div>
79
80
81
82
83 </div>
84 '''
html页面聚焦

  数据采集之re模块正则解析脚本

 1 # 糗事百科---糗图:https://www.qiushibaike.com/pic/
 2 import os
 3 import re
 4 import requests
 5 from fake_useragent import UserAgent
 6 UA=UserAgent()
 7 headers={
 8 'User-Agent':UA.random
 9 }
10 start_page=1
11 end_page=36
12 reg='<div class="article block untagged mb15".*?<h2>(.*?)</h2>.*?<img src="(.*?)" alt.*?</div>'#正则表达式编写
13
14
15 if not os.path.exists('糗图'):
16 os.mkdir('糗图')
17
18 for page in range(start_page,end_page):
19 print(f'第{page}页糗图数据获取中............')
20 url = f'https://www.qiushibaike.com/pic/page/{page}/?s=5215717'
21 response=requests.get(url,headers=headers)
22 res=re.findall(reg,response.text,re.S)#正则进行匹配提取解析----注意re.S处理换行和回车
23 # print(res)
24 for pic in res:
25 pic_url='https:'+pic[1]
26 pic_name=pic[1].rsplit('/')[-1]
27 pic_path=os.path.join('糗图',pic_name)
28
29 if pic_name in os.listdir('糗图'):
30 continue
31 response_pic=requests.get(pic_url,headers=headers)
32
33 with open(pic_path,'wb')as f:
34  f.write(response_pic.content)
35 print(f'{pic_name}下载成功!!!')
正则解析

2.xpath解析  

依赖模块:
    xlml pip install lxml
模块导入:
    from lxml.html.clean import etree #python 3.5之后
    #from lxml import etree #python 3.5之前
解析原理:
    实例化一个etree类型的对象,且将即将被解析的页面源码数据加载到该对象中
    调用该对象中的xpath方法结合着不同的xpath表达式进行标签定位和数据提取
实例化对象:
    tree=etree.parse(fileName)----本地文件
    tree=etree.HTML(page_text)----获取的页面内容
xpath方法返回值永远是一个列表
xpath表达式中最左侧的/和//的区别:
    /表示必须从根标签进行定位(从html开始)
    //表示可以从任意位置标签定位
xpath表达式中非最左侧的/和//的区别:
    /表示直属层级目录
    //表示后代多层级目录
xpath标签定位:
     属性定位:
        tree.xpath('//div[@id="content"]') tree.xpath('//div[@class="c1"]')     
     tree.xpath('//div/sapn|/p')找到div下所有直属的span和p标签
    层级、索引定位: 
        tree.xpath('//div[@id="content"]/ul/li[2]')找到id为content的div下ul中的第2(索引从1开始)个直系li标签 
    逻辑运算定位: 
       tree.xpath('//a[@id="content" and @href=""]')找到id为content并且href为空的a标签 
       tree.xpath('//a[@id="content" or @href=""]')找到id为content或者href为空的a标签 
    模糊定位: 
       tree.xpath('//div[contains(@class,"c")]')找到class属性中含有c的div标签 
       tree.xpath('//div[start-with(@class,"c")]')找到class属性以c开头的div标签 
    位置属性定位: 
       tree.xpath('//title[@*]") 选取所有带有属性的 div 元素 
xpath取值: 
    取文本 
       /text():获取的是标签下直系的文本数据 
       //text():获取的是标签下所有的文本数据 
   取属性@ 
      /@attr 
更多可参考菜鸟教程:https://www.runoob.com/xpath/xpath-syntax.html
    案例一:糗事百科----文字:https://www.qiushibaike.com/text/
 1 # 糗事百科----文字:https://www.qiushibaike.com/text/
 2 import requests
 3 from lxml.html.clean import etree
 4 from fake_useragent import UserAgent
 5 UA=UserAgent()
 6 headers={'User-Agent':UA.random}
 7
 8 url_model='https://www.qiushibaike.com/text/page/%d/'
 9 fp=open('糗事百科---段子.txt','w',encoding='utf-8')
10 for page in range(1,14):
11 url=format(url_model%page)
12 response=requests.get(url,headers=headers)
13 tree=etree.HTML(response.text)
14 nick_list=tree.xpath('//div[@class="author clearfix"]/a[2]/h2/text()|//div[@class="author clearfix"]/span[2]/h2/text()')#解析昵称(使用了‘|’多条件选择匹配)
15 link_list=tree.xpath('//a[@class="contentHerf"]/@href')#解析内容的连接
16
17 content_list=[]
18 url_='https://www.qiushibaike.com'
19 for nick,link in zip(nick_list,link_list):
20 content_list.append((nick,url_+link))
21 # print(content_list)
22
23 for i,content in enumerate(content_list):
24 nick_name=content[0]
25 url_detail=content[1]
26 response_detail=requests.get(url_detail,headers=headers)
27 content_tree=etree.HTML(response_detail.text)
28
29 content_detail=content_tree.xpath('//div[@class="content"]/text()')
30 content_str='\n'.join(content_detail)
31 str='<'+nick_name.strip('\n')+'>\n'+content_str+'\n\n'
32  fp.write(str)
33 print(f'第{page}页第{i}条段子下载完成!')
34 fp.close()
xpath解析之糗图段子采集

     案例二:彼岸图图片采集:http://pic.netbian.com/

 1 '''
 2 彼岸图图片采集:http://pic.netbian.com/
 3 '''
 4 import os
 5 from lxml.html.clean import etree#xpath解析
 6 import requests
 7 from fake_useragent import UserAgent
 8 UA=UserAgent()
 9 headers={'User-Agent':UA.random}
10
11 #首页获取图片分类
12 url_index='http://pic.netbian.com'
13 response_index=requests.get(url_index,headers=headers)
14 response_index.encoding='gbk'
15 # tree = etree.parse(filename)#解析本地html文件
16 tree_index=etree.HTML(response_index.text)
17 picture_list=tree_index.xpath('//div[@class="classify clearfix"]/a/@href')
18 title_list=tree_index.xpath('//div[@class="classify clearfix"]/a/text()')
19 all_pictures=[]
20 for title,pic in zip(title_list,picture_list):
21 all_pictures.append((title,url_index+pic))
22 print('图片分类如下:')
23 for i,j in enumerate(all_pictures):
24 print(i,'\t',j[0])
25
26 # print(all_pictures)
27 #输入数字序号进行专辑分类采集:
28 num=int(input('请输入你要采集的图片的序号>>>>'))
29
30
31 #创建专辑文件夹
32 dir_pic=all_pictures[num][0]
33 if not os.path.exists(dir_pic):
34  os.mkdir(dir_pic)
35
36 #请求每个分类的第一页拿到总页码,并保存第一页的内容
37 print(f'{dir_pic}加载中......')
38 print('获取第1页图片:')
39 url=all_pictures[num][1]
40
41 #请求首页,获取首页数据及总页码
42 response = requests.get(url, headers=headers)
43 tree = etree.HTML(response.text)
44 pages = int(tree.xpath('//div[@class="page"]/a[7]/text()')[0])
45 print(pages,type(pages))
46
47 li_list = tree.xpath('//div[@class="slist"]/ul[@class="clearfix"]/li')
48 for i,li in enumerate(li_list):
49 name = ''
50 if li.xpath('./a/b/text()'):
51 name = li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk')
52 url_ = url_index + li.xpath('./a/img/@src')[0]
53
54 file_name = name + url_.rsplit('/')[-1]
55 response_ = requests.get(url_, headers=headers)
56 file_path = os.path.join(dir_pic, file_name)
57 if file_name in os.listdir(dir_pic):
58 continue
59 with open(file_path, 'wb')as f:
60  f.write(response.content)
61 print(f"第1页第{i}张{file_name}下载完成!")
62 print(url)
63
64 #第二页开始爬取
65 for i in range(2,pages):
66 url_=url+f'index_{i}.html'
67 response = requests.get(url_, headers=headers)
68 tree = etree.HTML(response.text)
69
70 li_list = tree.xpath('//div[@class="slist"]/ul[@class="clearfix"]/li')
71 for j,li in enumerate(li_list):
72 name = ''
73 if li.xpath('./a/b/text()'):
74 name =li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk')
75 url_ = url_index + li.xpath('./a/img/@src')[0]
76
77 file_name = name + url_.rsplit('/')[-1]
78 response_ = requests.get(url_, headers=headers)
79 file_path = os.path.join(dir_pic, file_name)
80 if file_name in os.listdir(dir_pic):
81 continue
82 with open(file_path, 'wb')as f:
83  f.write(response_.content)
84 print(f"第{i}页第{j}张{file_name}下载完成!")
xpath解析之彼岸图图片采集

3.bs4解析

依赖模块:1)bs4 pip install bs4
   (2)xlml pip install lxml
模块导入:
   from bs4 import BeautifulSoup
bs4解析原理1)实例化一个BeautifulSoup的对象,且将即将被解析的页面源码加载到该对象中
   (2)使用该对象中的属性或者方法进行标签定位和数据提取
使用方式:1)将本地存储的html文档加载到该对象中
      soup=BeautifulSoup(fp,'lxml')
   (2)将互联网上获取的html源码加载到该对象中
      soup=BeautifulSoup(page_text,'lxml')
内容解析:
1)定位标签
   a. soup.tagName返回一个标签 soup.div
   b. soup.find(’tagName',attr_=value)返回第一个标签 soup.find('div',class_='home')

   c. soup.find_all(’tagName',attr_=value)返回标签列表 soup.find('div',class_='home')

   d. soup.select('选择器')返回列表
      类选择器,id选择器,标签选择器,层级选择器(>表示一个层级,空格表示多个层级)soup.select('.tang > ul > li > a')

2)获取标签内容或者属性值
   a. element.string string获取的是标签中直系的文本内容
   b. element.text text获取的是标签中所有的文本内容
   c. element.attrs/element.attrs['属性']/soup.tagName['属性'] 获取标签的所有/指定属性值
 1 环境安装
 2 - 需要将pip源设置为国内源,阿里源、豆瓣源、网易源等
 3 - windows
 4 (1)打开文件资源管理器(文件夹地址栏中)
 5 (2)地址栏上面输入 %appdata%
 6 (3)在这里面新建一个文件夹 pip
 7 (4)在pip文件夹里面新建一个文件叫做 pip.ini ,内容写如下即可
 8 [global]
 9 timeout = 6000
10 index-url = https://mirrors.aliyun.com/pypi/simple/
11 trusted-host = mirrors.aliyun.com
12 - linux
13 (1)cd ~
14 (2)mkdir ~/.pip
15 (3)vi ~/.pip/pip.conf
16 (4)编辑内容,和windows一模一样
17 - 需要安装:pip install bs4
18  bs4在使用时候需要一个第三方库,把这个库也安装一下
19  pip install lxml
20 基础使用
21 使用流程:
22 - 导包:from bs4 import BeautifulSoup
23 - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
24 (1)转化本地文件:
25 - soup = BeautifulSoup(open('本地文件'), 'lxml')
26 (2)转化网络文件:
27 - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
28 (3)打印soup对象显示内容为html文件中的内容
29
30 基础巩固:
31 (1)根据标签名查找
32 - soup.a 只能找到第一个符合要求的标签
33 (2)获取属性
34 - soup.a.attrs 获取a所有的属性和属性值,返回一个字典
35 - soup.a.attrs['href'] 获取href属性
36 - soup.a['href'] 也可简写为这种形式
37 (3)获取内容
38 - soup.a.string
39 - soup.a.text
40 - soup.a.get_text()
41  【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
42 (4)find:找到第一个符合要求的标签
43 - soup.find('a') 找到第一个符合要求的
44 - soup.find('a', title="xxx")
45 - soup.find('a', alt="xxx")
46 - soup.find('a', class_="xxx")
47 - soup.find('a', id="xxx")
48 (5)find_all:找到所有符合要求的标签
49 - soup.find_all('a')
50 - soup.find_all(['a','b']) 找到所有的a和b标签
51 - soup.find_all('a', limit=2) 限制前两个
52 (6)根据选择器选择指定的内容
53 select:soup.select('#feng')
54 - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
55 - 层级选择器:
56 div .dudu #lala .meme .xixi 下面好多级
57 div > p > a > .lala 只能是下面一级
58 【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
bs4安装与基础使用

  案例: 糗事百科----文字首页:https://www.qiushibaike.com/text/

 1 # 糗事百科----文字首页:https://www.qiushibaike.com/text/
 2 import requests
 3 from bs4 import BeautifulSoup
 4 from fake_useragent import UserAgent
 5 UA=UserAgent()
 6 headers={'User-Agent':UA.random}
 7
 8 url='https://www.qiushibaike.com/text/'
 9 response=requests.get(url,headers=headers)
10 soup=BeautifulSoup(response.text,'lxml')#依赖lxml模块,需提前安装
11
12 content_list=soup.select('.content>span')
13 for i,content in enumerate(content_list):
14 print(i+1,content.text.strip())
bs4解析之糗事百科段子采集

 

posted @ 2019-08-05 19:08  笑得好美  阅读(898)  评论(0编辑  收藏  举报