美文网首页python
正则、xpath、bs4的使用和语法

正则、xpath、bs4的使用和语法

作者: 心i_af0a | 来源:发表于2019-08-04 19:01 被阅读0次

    单字符匹配

    . 除换行符之外的任意字符
    \d 表示数字
    \D 匹配非数字
    \w 匹配单词字符[a-z,A-Z,0-9]
    \W 匹配非单词字符
    \s 匹配空白字符,空格,\n \t…
    \S 匹配非空白字符
    ^ 匹配以…开头
    $ 匹配以…结尾
    [0-9] => \d 匹配0-9

    多字符匹配(贪婪匹配)

    • 匹配*前面的字符任意次数
    • 匹配+前面的字符至少一次
      ?匹配?前面的字符0-1次
      {n,m}匹配{n,m}前面的字符n-m次
      多字符匹配(非贪婪匹配)
      *?
      +?
      ??
      其他
      ()分组
      |逻辑或
      \转义字符
      re模块下的方法
      re.compile():构建正则表达式对象
      re.match():从起始位开始匹配,单次匹配,如果匹配到结果立即返回,反之,返回None
      re.search():在整个字符串中进行匹配,单次匹配,如果匹配到结果立即返回,反之,返回None
      re.findall():匹配出整个字符串中,所有符合正则规则的结果,返回一个列表
      re.finditer():匹配出整个字符串中,所有符合正则规则的结果,返回的是一个可迭代对象
      re.sub():根据正则表达式进行字符串替换
      re.split():根据正则表达式进行分割

    正则的用法

    def get_rank_data(url='http://top.hengyan.com/dianji/default.aspx?p=1'):
        #构建请求头
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
        }
        # url, \目标url
        # data=None, \默认为None表示是get请求,如果不为None说明是get请求
        # timeout 设置请求的超时时间
        # cafile=None, capath=None, cadefault=False,:证书相关参数
        # context=None :忽略证书认证
        #urlopen不能添加请求头
        # response = request.urlopen(url=url,timeout=10)
    
        #添加请求头
        req = request.Request(url=url,headers=headers)
        response = request.urlopen(req,timeout=10)
    
        #响应状态码
        code = response.status
        #当前请求的url地址
        url = response.url
        print(code,url)
    
        b_content = response.read()
        # bytes -> str: decode
        # str -> bytes: encode
        # print(b_content)
        html = b_content.decode('utf-8')
        # print(html)
        # #文件操作
        # """
        # w:    w+:    wb:    wb+    a:    a+:    ab:    ab+:    r:    rb:
        # """
        # with open('hengyan.html','w') as file:
        #     file.write(html)
    
        #证据正则表达式解析数据
        # re.S 修饰:表示.可以匹配换行符
    
        pattern = re.compile('<div\sclass="list">(.*?)</div>',re.S)
        ul_str = re.findall(pattern,html)[0]
    
        pattern1 = re.compile('<ul.*?>(.*?)</ul>',re.S)
        li_strs = re.findall(pattern1,ul_str)[1:]
    
        for li_str in li_strs:
            # print(li_str)
            pattern = re.compile(
                '<li\sclass="num">(.*?)</li>'+
                '.*?<a.*?>(.*?)</a>'+
                '.*?<li.*?>(.*?)</li>'+
                '.*?<li.*?>(.*?)</li>'+
                '.*?<li.*?>(.*?)</li>'+
                '.*?<li.*?>(.*?)</li>',
                re.S
            )
    
            data = re.findall(pattern=pattern,string=li_str)[0]
            print(data)
    
        #提取下一页:
        if '下一页' in html:
            #说明还存在下一页
            pattern = re.compile('<span\sclass="pageBarCurrentStyle">(.*?)</span>',re.S)
            current_page = int(re.findall(pattern,html)[0])
            next_page = current_page+1
            #构造下一页的URL地址
            next_page_url = re.sub('\d+',str(next_page),url)
            print(next_page_url)
            get_rank_data(next_page_url)
        else:
            print('数据提取完毕')
    
    if __name__ == '__main__':
        get_rank_data()
    

    xpath

    安装:pip install lxml
    引用:from lxml import etree
    创建etree对象进行指定数据解析
    1.本地
    etree = etree.parse(‘本地路径’)
    etree.xpath(‘xpath表达式’)
    2.网络
    etree = etree.HTML(‘网络请求到页面的数据’)
    etree.xpath(‘xpath表达式’)
    常用的xpath表达式:
    1.属性定位:
    找到class属性值为song的div标签
    //div[@class=‘song’]
    2.层级索引定位
    找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
    //div[@class=‘tang’]/ul/li[2]/a
    3.逻辑运算
    找到href属性值为空且class属性值为du的a标签
    //a[@href=’’ and @class=‘du’]
    4.模糊匹配
    /表示获取某个标签下的文本内容 //div[@class=‘song’]/p[1]/text()
    //表示获取某个标签下的文本内容和所有子标签下的文本内容 //div[@class=‘tang’]//text()
    5.取属性
    //div[@class=‘tang’]//li[2]/a/@href

    class HengYanSpider(object):
    
        def __init__(self):
            self.first_url = 'http://all.hengyan.com/1/0_0_0_0_0_0_0_0_0_1.aspx'
            self.default_headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
            }
    
        def get_noval_url(self, url=None):
            url = self.first_url if not url else url
            """获取小说详情的url地址"""
            html = self.send_request(url)
            if html:
                # 解析数据(获取xpath解析器)
                etree_html = etree.HTML(html)
                noval_urls = etree_html.xpath('//li[@class="bookname"]/a[1]/@href')
                for noval_url in noval_urls:
                    self.get_noval_detail(noval_url)
    
                # 获取下一页
                if '下一页' in html:
                    # 说明还存在下一页
                    current_page = int(self.extract_first(etree_html.xpath('//span[@class="pageBarCurrentStyle"]/text()]')))
                    next_page = current_page + 1
                    next_page_url = re.sub('\d+.aspx', str(next_page)+'.aspx', url)
                    self.get_noval_url(next_page_url)
                else:
                    print('数据提取完毕')
            else:
                print('数据获取失败')
    
        def get_noval_detail(self, noval_url):
            """获取书籍详情的页面内容,解析数据"""
            html = self.send_request(noval_url)
            if html:
                # 解析数据(获取xpath解析器)
                etree_html = etree.HTML(html)
                # print('得到了详情页面')
                noval_dict = {}
                # 书号
                book_id = self.extract_first(etree_html.xpath('//div[@class="dh"]/p/label/text()'))
                noval_dict['book_id'] = re.search('\d+', book_id).group()
                # 热度
                noval_dict['hot'] = self.extract_first(etree_html.xpath('//p[@class="wendu"]/b/text()'))
                # 火车票
                noval_dict['hot_track'] = self.extract_first(
                    etree_html.xpath('//div[@class="piao"]/p[2]/span[@class="huocolor"]/text()'))
                # 冰票
                noval_dict['bing_track'] = self.extract_first(
                    etree_html.xpath('//div[@class="piao"]/p[2]/span[@class="bingcolor"]/text()'))
                # 金笔
                noval_dict['jingbi'] = self.extract_first(etree_html.xpath('//div[@class="jinbi"]//li[1]/p[2]/text()'))
                # 标题
                noval_dict['title'] = self.extract_first(etree_html.xpath('//h2/text()'))
                # 简介
                noval_dict['content'] = self.extract_first(
                    etree_html.xpath('//p[@class="intro ih1"]/text()|//p[@class="intro ih2"]/text()'))
                # 作者
                noval_dict['author'] = self.extract_first(etree_html.xpath('//div[@id="ainfo"]/p/span/a[2]/text()'))
    
                print(noval_dict)
                self.save_data(noval_dict)
    
        def save_data(self, noval_dict):
            """保存数据"""
            pass
    
        def extract_first(self, data, default=''):
            if len(data) > 0:
                return data[0]
            return default
    
        def send_request(self, url, header=None, data=None, method="GET"):
            """发送请求"""
            header = self.default_headers if not header else header
    
            if method == 'GET':
                # 发送get请求
                response = requests.get(url=url, params=data, headers=header)
            else:
                # 发送post请求
                response = requests.post(url=url, data=data, headers=header)
    
            if response.status_code == 200:
                # 请求成功,返回页面源码
                return response.text
    
    
    if __name__ == '__main__':
        spider = HengYanSpider()
        spider.get_noval_url()
    

    bs4(python独有简单便捷和高效)

    环境安装:pip install lxml bs4用到lxml库,如果没有安装过lxml库的时候,需要安装一下
    代码使用流程:
    核心思想:可以将html文档可以转换成BeautifulSoup对象,调用该对象中的属性和方法进行
    1.导包
    from bs4 import BeautifulSoup
    2.创建BeautifulSoup对象
    a.本地
    Beautiful(‘open(‘本地的html文件’)’,‘lxml’)
    b.网络
    Beautiful(‘网络请求到的页面数据’,‘lxml’)
    属性和方法:
    1.根据标签名查找
    soup.a 只能找到第一个符合要求的标签
    2.获取属性
    soup.a.attrs 获取a所有的属性和属性值,返回一个字典
    soup.a.attrs[‘href’] 获取href属性
    soup.a[‘href’] 也可简写为这种形式
    3.获取内容
    soup.a.string /text()
    soup.a.text //text()
    soup.a.get_text() //text()
    如果标签还是标签,那么string获取到的结果为none,而其他两个,可以获取文本内容
    4.find:找到第一个符合要求的标签
    soup.find(‘a’) 找到第一个符合要求的
    soup.find(‘a’,title=‘xxx’)
    soup.find(‘a’,alt=‘xxx’)
    soup.find(‘a’,class=‘xxx’)
    soup.find(‘a’,id=‘xxx’)
    5.find_All:找到所有符合要求的标签
    soup.find_All(‘a’)
    soup.find_All([‘a’,‘b’]) 找到所有的a和b标签
    soup.find_All(‘a’,limit=2) 限制前两个
    6.根据选择器选择指定的内容
    select:soup.select(’#feng’)
    常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
    层级选择器:
    div .dudu #lala .name .xixi 下面好多级 div//img
    div > p > a > .lala 只能是下面一级 div/img
    select选择器返回永远是列表,需要通过下标提取指定对象
    class HengYanSpider(object):
    
        def __init__(self):
            self.first_url = 'http://all.hengyan.com/1/0_0_0_0_0_0_0_0_0_1.aspx'
            self.default_headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
            }
    
        def get_noval_url(self, url=None):
            url = self.first_url if not url else url
            """获取小说详情的url地址"""
            html = self.send_request(url)
            if html:
                bs_soup = BeautifulSoup(html, 'lxml')
                lis = bs_soup.find_all(name='li', attrs={'class': 'bookname'})
                for li in lis:
                    # a_list = li.find_all(name='a')
                    # if len(a_list) > 0:
                    #     url = a_list[0].attrs['href']
                    a_list = li.select('a')
                    if len(a_list) > 0:
                        url = a_list[0].attrs['href']
                        self.get_noval_detail(url)
    
        def get_noval_detail(self, noval_url):
            """获取书籍详情的页面内容,解析数据"""
            html = self.send_request(noval_url)
            if html:
                # 解析数据(获取xpath解析器)
                bs_soup = BeautifulSoup(html, 'lxml')
                # print('得到了详情页面')
                noval_dict = {}
                # 书号
                book_id = bs_soup.select('div.dh p label')[0].get_text()
                noval_dict['book_id'] = re.search('\d+', book_id).group()
                # 热度
                noval_dict['hot'] = bs_soup.select('p.wendu b')[0].get_text()
                # 火车票
                noval_dict['hot_track'] = bs_soup.select('div.piao p')[1].select('.huocolor')[0].get_text()
                # 冰票
                noval_dict['bing_track'] = bs_soup.select('div.piao p')[1].select('.bingcolor')[0].get_text()
                
    
                print(noval_dict)
                # self.save_data(noval_dict)
    
        def save_data(self, noval_dict):
            """保存数据"""
            pass
    
        def extract_first(self, data, default=''):
            if len(data) > 0:
                return data[0]
            return default
    
        def send_request(self, url, header=None, data=None, method="GET"):
            """发送请求"""
            header = self.default_headers if not header else header
    
            if method == 'GET':
                # 发送get请求
                response = requests.get(url=url, params=data, headers=header)
            else:
                # 发送post请求
                response = requests.post(url=url, data=data, headers=header)
    
            if response.status_code == 200:
                # 请求成功,返回页面源码
                return response.text
    
    if __name__ == '__main__':
        spider = HengYanSpider()
        spider.get_noval_url()
    

    相关文章

      网友评论

        本文标题:正则、xpath、bs4的使用和语法

        本文链接:https://www.haomeiwen.com/subject/bswydctx.html