Python--爬虫数据解析,,页面解析和数据提取一


页面解析和数据提取

一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据 和 结构化的数据。

非结构化数据:先有数据,再有结构,(http://www.baidu.com)

结构化数据:先有结构、再有数据(https://www.qiushibaike.com/imgrank/page/3/)

不同类型的数据,我们需要采用不同的方式来处理。

常用的数据解析有正则(re)、bs4、xpath等。

正则使用参考

?

bs4

bs4解析原理

实例化一个BeautifulSoup的对象,需要将即将被解析的页面源码数据加载到对象中调用BeautifulSoup对象中的相关方法和属性进行标签定位和数据提取

?

bs4解析流程

?? 环境安装

pip install bs4

?? 导入模块

from bs4 import BeautifulSoup

?? 实例化一个BeautifulSoup对象

# 转化本地文件(将本地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中)soup = BeautifulSoup(open(‘本地文件‘), ‘lxml‘)# 转化网络文件(将从互联网上获取的页面源码数据加载到实例化好的BeautifulSoup对象中)soup = BeautifulSoup(‘字符串类型或者字节类型‘, ‘lxml‘)

?? 调用BeautifulSoup对象中的相关属性和方法进行标签的定位

?

bs4基本语法

1.根据标签名查找

soup.tagName- soup.a只能找到第一个符合要求的标签

2.获取属性

soup.tagName[‘attrName‘]- soup.a.attrs  获取a所有的属性和属性值,返回一个字典- soup.a.attrs[‘href‘]   获取href属性- soup.a[‘href‘]   也可简写为这种形式

3.获取内容

.string:获取直系的文本内容.text:获取所有的文本内容- soup.a.string      获取a标签的直系文本- soup.a.text     这是属性,获取a子类的所有文本- soup.a.get_text()  这是方法,获取a标签子类的所有文本【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容

4.属性定位find方法

soup.find(‘tagName‘, attrName=‘value‘)- soup.find(‘a‘)  找到第一个符合要求的a标签- soup.find(‘a‘, title="xxx") 找具有title=xxx属性的第一个a标签- soup.find(‘li‘, alt="xxx")找到具有alt=xxx属性的第一个li标签- soup.find(‘ul‘, class_="xxx")找到具有class=xxx属性的第一个ui标签- soup.find(‘div‘, id="xxx")找到具有id=xxx属性的第一个div标签

5.属性定位find_all方法

soup.find_all(‘tagName‘, attrName=‘value‘),返回值为列表- soup.find_all(‘a‘)#找到所有a标签- soup.find_all(‘a‘, title=‘xxx‘)找到具有title=xxx属性的所有a标签- soup.find_all(‘div‘, class_=‘xxx‘, limit=3)找到具有class=xxx属性的前三个标签

6.选择器定位select方法

soup.select(‘选择器‘)- soup.select(‘.song‘)找到类属性为song的标签- soup.select(‘#song‘)找到id属性为song的标签- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器- 层级选择器:        div .haha #wan    空格表示多个层级        div > p > a > img >表示一个层级

?

bs4爬虫示例

?? 爬取三国整篇内容

#爬取三国整篇内容(章节名称和章节内容) http://www.shicimingju.com/book/sanguoyanyi.htmlimport requestsfrom bs4 import BeautifulSoupfp = open(‘sanguo.txt‘,‘w‘,encoding=‘utf-8‘)headers = {    ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36‘}main_url = ‘http://www.shicimingju.com/book/sanguoyanyi.html‘page_text = requests.get(url=main_url, headers=headers).text#解析出章节名称和章节详情的urlsoup = BeautifulSoup(page_text, ‘lxml‘)a_list = soup.select(‘.book-mulu > ul >li > a‘) #返回的列表中存储的是一个个a标签for a in a_list:    title = a.string    detail_url = ‘http://www.shicimingju.com‘+a[‘href‘]    detail_page_text = requests.get(detail_url, headers=headers).text    #解析详情页中的章节内容    soup = BeautifulSoup(detail_page_text, ‘lxml‘)    content = soup.find(‘div‘, class_=‘chapter_content‘).text    fp.write(title+‘:‘+content+‘\n‘)    print(title,‘下载成功!‘)fp.close

?

xpath

xpath解析原理

实例化一个etree的对象,然后将即将被解析的页面源码加载到该对象中使用etree对象中xpath方法结合着不同形式的xpath表达式实现标签定位和数据提取

?

xpath解析流程

?? 环境安装

pip install lxml

?? 导入模块

from lxml import etree

?? 实例化一个etree对象

# 转化本地文件(将本地存储的一个html文档中的数据加载到实例化好的tree对象中)tree = etree.parse(‘test.html‘)
# 转化网络文件(将从互联网上获取的页面源码数据加载到实例化好的tree对象中)tree = etree.HTML(page_text)

?

xpath基本语法

xpath表达式:xpath方法的返回值一定是一个列表最左侧的/表示:xpath表达式一定要从根标签逐层进行标签查询和定位最左侧的//表示:xpath表达式可以从任意位置定位标签非最左侧的/:表示一个层级非最左侧的//:表示夸多个层级属性定位://tagName[@attrName=‘value‘]索引定位://tagName[index] 索引从1开始

1.取文本:

- /text():直系文本内容- //text():所有文本内容

2.取属性:

/@attrName

示例

准备html内容

<html><body><div>    <ul>         <li class="item-0"><a href="link1.html">first item</a></li>         <li class="item-1"><a href="link2.html">second item</a></li>         <li class="item-inactive"><a href="link3.html">third item</a></li>         <li class="item-1"><a href="link4.html">fourth item</a></li>         <li class="item-0"><a href="link5.html">fifth item</a></li></ul> </div></body></html>

1.获取所有的标签

from lxml import etreehtml = etree.parse(‘hello.html‘)result = html.xpath(‘//li‘)print(result)   # 打印<li>标签的元素集合result_text = html.xpath(‘//li/text()‘)

2.获取标签的所有class属性

from lxml import etreehtml = etree.parse(‘hello.html‘)result = html.xpath(‘//li/@class‘)print result结果是[‘item-0‘, ‘item-1‘, ‘item-inactive‘, ‘item-1‘, ‘item-0‘]

3.继续获取<li>标签下href为 link1.html 的 <a> 标签

from lxml import etreehtml = etree.parse(‘hello.html‘)result = html.xpath(‘//li/a[@href="link1.html"]‘)print result运行结果[<Element a at 0x10ffaae18>]

4.获取最后一个 <li> 的 <a> 的 href

from lxml import etreehtml = etree.parse(‘hello.html‘)result = html.xpath(‘//li[last()]/a/@href‘)# 谓语 [last()] 可以找到最后一个元素print result运行结果[‘link5.html‘]

?

xpath 爬虫示例

?? 示例1

#爬取糗事百科中段子内容和作者名称import requestsfrom lxml import etreeheaders = {    ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36‘}url = ‘https://www.qiushibaike.com/text/‘page_text = requests.get(url=url, headers=headers).text#解析内容tree = etree.HTML(page_text)div_list = tree.xpath(‘//div[@class="col1 old-style-col1"]/div‘)for div in div_list:    author = div.xpath(‘./div[1]/a[2]/h2/text()‘)[0] #实现局部解析    content = div.xpath(‘./a[1]/div/span//text()‘)    content = ‘‘.join(content)        print(author, content)

?? 示例2

# http://pic.netbian.com/4kmeinv/  联系xpath和解决中文乱码问题dirName = ‘./meinvLibs‘if not os.path.exists(dirName):    os.mkdir(dirName)url = ‘http://pic.netbian.com/4kmeinv/index_%d.html‘for page in range(1,11):    if page == 1:        new_url = ‘http://pic.netbian.com/4kmeinv/‘    else:        new_url = format(url%page)    page_text = requests.get(url=new_url, headers=headers).text    tree = etree.HTML(page_text)    a_list = tree.xpath(‘//div[@class="slist"]/ul/li/a‘)    for a in a_list:        img_src = ‘http://pic.netbian.com‘ + a.xpath(‘./img/@src‘)[0]        img_name = a.xpath(‘./b/text()‘)[0]        img_name = img_name.encode(‘iso-8859-1‘).decode(‘gbk‘)        img_data = requests.get(url=img_src, headers=headers).content        imgPath = dirName+‘/‘+img_name+‘.jpg‘        with open(imgPath, ‘wb‘) as fp:            fp.write(img_data)            print(img_name, "下载成功!!!")

?? 示例3

# http://sc.chinaz.com/jianli/free.html 爬取简历模板前五页  通过xpath解析import requests, osfrom lxml import etreesave_resume_dir = ‘./jianli‘if not os.path.exists(save_resume_dir):    os.mkdir(save_resume_dir)headers = {    ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36‘}url = ‘http://sc.chinaz.com/jianli/free_%d.html‘for page in range(1,6):    if page == 1:        new_url = ‘http://sc.chinaz.com/jianli/free.html‘    else:        new_url = format(url%page)    page_text = requests.get(url=new_url, headers=headers).text  #向每一页发起请求    tree = etree.HTML(page_text)    a_list = tree.xpath(‘//div[@id="container"]/div/a‘)   #获取每一页中所有的简历    for a in a_list:        resume_url = a.xpath(‘./@href‘)[0]  #得到每一份简历的url地址        resume_anme = a.xpath(‘./img/@alt‘)[0]  #得到每一份简历的名字        resume_anme = resume_anme.encode(‘iso-8859-1‘).decode(‘utf-8‘)  #解决简历名字乱码        resume_text = requests.get(url=resume_url, headers=headers).text  #向每一份简历的页面发起请求        tree = etree.HTML(resume_text)        resume_down_url = tree.xpath(‘//div[@class="down_wrap"]/div[2]/ul/li[1]/a/@href‘)[0]  #对每一份简历页面请求数据进行解析,得到下载的url        resume_down_text = requests.get(url=resume_down_url, headers=headers).content  #下载每一份简历        resume_path = save_resume_dir + ‘/‘ + resume_anme + ‘.rar‘        with open(resume_path, ‘wb‘) as fp:            fp.write(resume_down_text)            print(resume_anme+‘简历模板下载成功!!!‘)

?? 示例4

# 爬取梨视频任意板块最热视频  https://www.pearvideo.com/category_8import requestsfrom lxml import etreeimport reheaders = {    ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36‘}main_url = ‘https://www.pearvideo.com/category_8‘main_text = requests.get(url=main_url, headers=headers).texttree = etree.HTML(main_text)div_list = tree.xpath(‘//*[@id="listvideoListUl"]/li‘)for li in div_list:    detile_url = ‘https://www.pearvideo.com/‘ + li.xpath(‘./div/a/@href‘)[0]  #获取视频详情页    title = li.xpath(‘./div/a/div[2]/text()‘)[0] + ‘.mp4‘  #获取视频名字    detile_page_text = requests.get(url=detile_url, headers=headers).text  #向视频详情页发起请求    ex = ‘srcUrl="(.*?)",vdoUrl‘   #通过正则获取js动态加载的数据    video_url = re.findall(ex, detile_page_text, re.S)[0]  #解析出视频url的地址    video_data = requests.get(video_url, headers=headers).content   #对视频url发起请求进行下载    with open(f‘./video/{title}‘, ‘wb‘) as fp:        fp.write(video_data)

Python--爬虫数据解析

评论关闭