爬虫(四)--正则应用,xml,xpath

一、正则应用

猫眼电影项目(封装)

需求:爬取猫眼电影top100,并筛选出电影名、主演、上映时间、评分信息。

1.取dl
在这里插入图片描述
在这里插入图片描述
2.取dd
在这里插入图片描述
在这里插入图片描述
3.取电影名
在这里插入图片描述
4.取主演
在这里插入图片描述
5.取上映时间
在这里插入图片描述
6.取评分
在这里插入图片描述

import requests,re,json

class Maoyan():
    def __init__(self,url):
        self.url = url
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
        }
        self.movie_list = []
        self.parse()
    def parse(self):
        # 爬取10页
        for i in range(10):
            url = self.url+'?offset=%s'%(i*10)
            response = requests.get(url,headers=self.headers)
            # print(response.text)
            # 提取信息
            # 电影名、主演、上映时间、评分
            dl_pattern = re.compile(r'<dl class="board-wrapper">(.*?)</dl>',re.S)
            dl = dl_pattern.search(response.text).group()
            dd_pattern = re.compile(r'<dd>(.*?)</dd>',re.S)
            dd = dd_pattern.findall(dl)
            movie_name_pattern = re.compile(r'title="(.*?)"')
            role_pattern = re.compile(r'<p class="star">(.*?)</p>',re.S)
            date_pattern = re.compile(r'<p class="releasetime">(.*?)</p>')
            score_pattern = re.compile(r'<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>')
            for one in dd:
                item = {}
                movie_name = movie_name_pattern.search(one).group()
                role = role_pattern.search(one).group(1).strip()[3:]
                date = date_pattern.search(one).group(1)[5:]
                score = score_pattern.search(one).group(1)+score_pattern.search(one).group(2)
                item = {'movie_name':movie_name,'role':role,'date':date,'score':score}
                self.movie_list.append(item)
        # print(self.movie_list)
        # 将电影信息写入到json文件中
        with open('movie.json','w',encoding='utf-8') as fp:
            json.dump(self.movie_list,fp)

if __name__ == '__main__':
    base_url = 'https://maoyan.com/board/4'
    Maoyan(base_url)
    # 从json文件中读取信息
    with open('movie.json','r') as fp:
        movie_list = json.load(fp)
    # 就可以任意操作了
    for movie in movie_list:
        print(movie)

json文件储存的是unicode编码,这样更方便传输,避免因为编码不同而出现的错误。
在这里插入图片描述

股吧项目

需求:取12页的阅读数,评论数,标题,作者,更新时间,详情页url信息

1.取ul
在这里插入图片描述
在这里插入图片描述
2.取li

3.取阅读数,评论数

4.取标题

5.取作者

6.取更新时间

7.取详情页url

import requests,re,json

base_url = 'http://guba.eastmoney.com/default,99_%s.html'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
infos = []
for i in range(1,13):
    response = requests.get(base_url%i,headers=headers)
    ul_pattern = re.compile(r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)
    ul = ul_pattern.search(response.text).group(1)
    li_pattern = re.compile(r'<li>(.*?)</li>',re.S)
    li = li_pattern.findall(ul)
    click_comment_pattern = re.compile(r'<cite>(.*?)</cite>(.*?)<cite>(.*?)</cite>',re.S)
    title_pattern = re.compile(r'title="(.*?)" class="note">')
    author_pattern = re.compile(r'<font>(.*?)</font></a>')
    time_pattern = re.compile(r'<cite class="last">(.*?)</cite>')
    url_pattern = re.compile(r'</em> <a href="(.*?)" title="')
    for one in li:
        click = click_comment_pattern.search(one).group(1).strip()
        comment = click_comment_pattern.search(one).group(3).strip()
        if title_pattern.search(one):
            title = title_pattern.search(one).group(1)
        else:
            title = ''
        author = author_pattern.search(one).group(1)
        time = time_pattern.search(one).group(1)
        if url_pattern.search(one):
            url = 'http://guba.eastmoney.com'+url_pattern.search(one).group(1)
        else:
            url = ''
        item = {'click':click,'comment':comment,'title':title,'author':author,'time':time,'url':url}
        infos.append(item)
print(infos)

封装

import requests,re,json

class Guba():
    def __init__(self,base_url):
        self.base_url = base_url
        self.infos = []
        self.get_info()
    def get_content(self,url):
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        if response.status_code==200:
            return response.text
    def get_info(self):
        for i in range(1, 13):
            html = self.get_content(self.base_url%i)
            ul_pattern = re.compile(
                r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)
            ul = ul_pattern.search(html).group(1)
            li_pattern = re.compile(r'<li>(.*?)</li>', re.S)
            li = li_pattern.findall(ul)
            click_comment_pattern = re.compile(
                r'<cite>(.*?)</cite>(.*?)<cite>(.*?)</cite>', re.S)
            title_pattern = re.compile(r'title="(.*?)" class="note">', re.S)
            author_pattern = re.compile(r'<font>(.*?)</font></a>', re.S)
            time_pattern = re.compile(r'<cite class="last">(.*?)</cite>', re.S)
            url_pattern = re.compile(r'</em> <a href="(.*?)" title="', re.S)
            for one in li:
                click = click_comment_pattern.search(one).group(1).strip()
                comment = click_comment_pattern.search(one).group(3).strip()
                if title_pattern.search(one):
                    title = title_pattern.search(one).group(1)
                else:
                    title = ''
                author = author_pattern.search(one).group(1)
                time = time_pattern.search(one).group(1)
                if url_pattern.search(one):
                    url = 'http://guba.eastmoney.com' + url_pattern.search(one).group(1)
                else:
                    url = ''
                item = {'click': click, 'comment': comment, 'title': title,
                        'author': author, 'time': time, 'url': url}
                self.infos.append(item)
        with open('guba_oop.json','w',encoding='utf-8') as fp:
            json.dump(self.infos,fp)
if __name__ == '__main__':
    Guba('http://guba.eastmoney.com/default,99_%s.html')
    with open('guba.json', 'r') as fp:
        info = json.load(fp)
    for one in info:
        print(one)

二、xml

(一)什么是xml

  • xml称为可扩展标记语言
  • xml具有自描述特性,是一种半结构化数据
  • xml的设计宗旨是用来传输数据,也可以作为配置文件记录一些重要的配置信息

(二)xml和html的区别

1.语法要求不同

  1. 在html中不区分大小写;xml中严格区分

  2. 在html中,如果上下文清楚地显示出段落或者列表在何处结尾,那么可以省略</p>或者</li>标记;在xml中,是严格的树状结构,绝不能省略任何标记

  3. 在xml,拥有单个标记而没有匹配的结束标记的元素,必须用一个/字符作为结尾。

    <a href='XXXXXXXX'/>

  4. 在xml中,属性值必须封装在引号中;在html中,引号可用可不用。

  5. 在html中,属性名可以没有属性值;xml必须有。

  6. 在xml中,空白部分不会被解析器自动删除;html是会过滤掉空格的。

2.作用不同

xml主要是用来传输数据的。

html主要是用来显示数据,以及更好的显示数据的。

3.标记不同

xml没有固定的标记。

html的标签是固定的。

三、xpath

(一)什么是xpath

xpath是一种语法,用来提取xml或者html页面内容的语法。

(二)xpath语法内容

  • 元素:指一个xml的标签以及标签的所有内容

  • 属性:class、name

  • 内容:a标签的内容就是‘\n aaa\n 1’和‘\n 2’,b标签的内容就是bbb

    <a>
    	aaa
    	1<b>bbb</b>
    2</a>
    
  • 标签:和元素一样

1.选取节点

  • nodename:选取此标签的所有子标签
  • /:从根节点开始选取
  • //:从任意位置开始选取
  • .:选取当前节点
  • …:选取父节点
  • @:选取属性
  • text():选取内容

2.谓语

英语中的谓语用来限定。

xpath中的谓语也是用来限定选取的内容的。

  • /bookstore/book[1]:表示取bookstore下面的第一个book标签
  • /bookstore/book[last()]:表示取bookstore下面的最后一个book标签
  • /bookstore/book[last()-1]:表示取bookstore下面的倒数第二个book标签
  • /bookstore/book[position()>1]:表示从bookstore下面的第二本书开始取
  • //title[@lang]:取有lang属性的title标签
  • //title[@lang=“eng”]:取有lang属性,且lang属性值为eng的title标签

3.选取未知节点

  • *:匹配任意节点
  • @*:匹配任意属性

4.选取若干路径

  • //title|//price:选取所有的title标签price标签

四、在python中如何使用xpath

通过lxml模块,可以使用xpath语法筛选元素。

方法

导包

from lxml import etree

方法一

将字符串形式的xml内容,解析成element对象的方法

html_element = etree.HTML(html_str)

from lxml import etree

text = """
<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>
"""
html = etree.HTML(text)
# print(html)    # <Element html at 0x3b62e48>
html_str = etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8')
print(html_str)

:tostring方法的返回值是bytes类型,转换为string类型需要解码。

方法二

将一个html文件转化成element对象的方法

html = etree.parse('demo.html')

etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8')

当使用parse方法解析一个xml或者html文件时,语法必须严格按照xml的标签语法,且标签必须对应。

demo.html

<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"><span class="bold">third item</span>></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>

py文件

from lxml import etree

html = etree.parse('demo.html')
# print(html)    # <lxml.etree._ElementTree object at 0x0000000003B51F48>
print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))

element对象可以调用xpath方法

html_element.xpath(),返回值都是一个存放element对象的列表,还可以继续调用xpath方法,继续筛选元素。

from lxml import etree

text = '''
<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" class="a_class_1">aaaa</a>
         <span class="span_item1">span_text1</span>
      </li>
      <li class="item-1">
            test
         <a href="link4.html" class="a_class_0">fourth item
            <span class="span_item2">span_text2</span></a>
      </li>
      <li class="item-0">
         <a href="link5.html" class="bold">fifth item</a>
      </li>
    </ul>
</div>
'''
html = etree.HTML(text)
# print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))
'''
<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" class="a_class_1">aaaa</a>
         <span class="span_item1">span_text1</span>
      </li>
      <li class="item-1">
            test
         <a href="link4.html" class="a_class_0">fourth item
            <span class="span_item2">span_text2</span></a>
      </li>
      <li class="item-0">
         <a href="link5.html" class="bold">fifth item</a>
      </li>
    </ul>
</div>
</body>
</html>
'''
# 获取所有的 <li> 标签
li_list = html.xpath('//li')
# print(li_list)
# 继续获取<li> 标签的所有 class属性
li_class_list = html.xpath('//li/@class')
# print(li_class)
# 继续获取<li>标签下href 为 link1.html 的 <a> 标签
li_a_href = html.xpath('//li/a[@href="link1.html"]')
# print(li_a_href)
# 获取<li> 标签下的所有 <span> 标签(包括孙子span)
li_span = html.xpath('//li//span')
# print(li_span)
# 获取 <li> 标签下的<a>标签里的所有 class
li_a_class = html.xpath('//li/a/@class')
# print(li_a_class)
# 获取最后一个 <li> 的 <a> 的 href
lastli_a_href = html.xpath('//ul/li[last()]/a/@href')
# print(lastli_a_href)
# 获取倒数第二个元素的内容
con = html.xpath('//*[last()-1]/text()')
# print(con)
# 获取 class 值为 bold 的标签名
bold = html.xpath('//*[@class="bold"]')
print(bold[0].tag)
from lxml import etree

html = '''
<bookstore>
    <title>新华书店</title>
    <book href="http://www.langlang2017.com/">
        <title lang="eng">Harry Potter</title>
        <price>29.99</price>
    </book>
    <book>
        <title lang="zh">Learning XML</title>
        <price>39.95</price>
    </book>
    <book href="www.baidu.com">
        <title>python 大全</title>
        <price>99.95</price>
    </book>
</bookstore>
'''
tree = etree.HTML(html)
# print(etree.tostring(tree,pretty_print=True,encoding='utf-8').decode('utf-8'))
# (1)获取文档中的所有book节点的第一个book节点
first_book = tree.xpath('//book[1]')
# print(first_book)
# (2)获取第一个book节点
first_book = first_book[0]
# (3)获取first_book当前节点下的href
href = first_book.xpath('.//@href')
# print(href)
# (4)获取当前节点的父节点下的book节点的href属性
href2 = first_book.xpath('../book/@href')
# print(href2)
# (5)获取价格小于40的书的书名
bookname = tree.xpath('//book[price<40]/title/text()')
# print(bookname)
# (6)获取价格等于99.95的书的书名
bookname2 = tree.xpath('//book[price=99.95]/title/text()')
# print(bookname2)
# (7)获取book标签下面的title和price标签
title_price = tree.xpath('//book/title|//book/price')
# print(title_price)
# (8)获取属性href含有baidu字符串的book标签,获取此标签的书名
title = tree.xpath('//book[contains(@href,"baidu")]/title/text()')
# print(title)
# (9)获取前面两个属于bookstore标签的子标签的book标签,获取此标签的书名
title2 = tree.xpath('//bookstore/book[position()<3]/title/text()')
# print(title2)
# (10)匹配任意有属性的节点
result = tree.xpath('//*[@*]')
# print(result)
# (11)获取所有带有属性title标签,获取此标签的内容
result2 = tree.xpath('//title[@*]/text()')
print(result2)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章