爬虫正则+bs4+xpath+综合实战详解

Day3 - 1.数据解析概述_哔哩哔哩_bilibili

聚焦爬虫:爬取页面中指定的页面内容

                编码流程:指定url -> 发起请求 -> 获取响应数据 -> 数据解析 -> 持久化存储

数据解析分类:正则、bs4、xpath(本教程的重点)

数据解析原理概述:解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储

                                1.进行指定标签的定位
                                2.标签或者标签对应的属性中存储的数据值进行提取(解析)

图片的爬取

图片是以二进制方式存储的,复制图片链接输入浏览器可以得到图片对应的url

import requests

url = 'https://img-blog.csdnimg.cn/09ad194be31144e9b628bcd26916c144.png'
# content返回二进制形式的图片数据
image_data = requests.get(url).content

with open('picture.png', 'wb') as fp:
    fp.write(image_data)

由于糗事百科停运了,所以找了个美女照片网站

美女写真图片大全_3g壁纸 (3gbizhi.com)

对图片进行检查,看到图片的url都是放在img标签里的,而src后面的值就是它的url

观察图片的层级关系,发现都在

    下,在
  • import re
    import requests
    import os
    
    if not os.path.exists('./girls_picture'):
        os.makedirs('girls_picture')
    
    url = 'https://www.3gbizhi.com/meinv/mnxz/'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
    }
    response = requests.get(url, headers=headers)
    page_text = response.text
    
    # 使用聚焦爬虫对页面的信息进行解析
    ex = '
  • .*?' img_src_list = re.findall(ex, page_text, re.S) new_img_src_list = [] for i in img_src_list: i = i[51:] new_img_src_list.append(i) print(new_img_src_list) for src in new_img_src_list: image_data = requests.get(src, headers=headers).content image_name = src.split('/')[-1] image_path = 'girls_picture' + '/' + image_name with open(image_path, 'wb') as fp: fp.write(image_data) print(image_name + '下载成功')
  • 多页爬取

    我们发现翻页的url变动是有规律的,因此只需for循环更改index后面的数字

    import re
    import requests
    import os
    
    if not os.path.exists('./girls_picture'):
        os.makedirs('girls_picture')
    
    url = 'https://www.3gbizhi.com/meinv/mnxz/index_%d.html'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
    }
    for i in range(1, 4):
        new_url = format(url % i)
    
        response = requests.get(new_url, headers=headers)
        page_text = response.text
    
        # 使用聚焦爬虫对页面的信息进行解析
        ex = '
  • .*?' img_src_list = re.findall(ex, page_text, re.S) new_img_src_list = [] for i in img_src_list: i = i[51:] new_img_src_list.append(i) print(new_img_src_list) for src in new_img_src_list: image_data = requests.get(src, headers=headers).content image_name = src.split('/')[-1] image_path = 'girls_picture' + '/' + image_name with open(image_path, 'wb') as fp: fp.write(image_data) print(image_name + '下载成功')
  • bs4

    bs4只能被应用在python中

    原理:1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
               2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取

    对象的实例化:1.将本地的html文档中的数据加载到该对象中
                            fp = open('./test.html','r',encoding=' utf-8'
                            soup = BeautifulSoup(fp,'Ixml')

    from bs4 import BeautifulSoup
    
    # 将本地的html文件加载倒BeautifulSoup对象中
    fp = open('sogpu.html', 'r', encoding='utf-8')
    soup = BeautifulSoup(fp, 'lxml')
    print(soup)

                           2.将互联网上获取的页面源码加载到该对象中
                            page text = response.text
                            soup = BeatifulSoup(page text,'xml')

    具体使用

    1.soup.tagName:返回html中第一次出现tagName的标签:

    print(soup.a)  # 打印a标签
    
    '''
    微信
    '''

    2.soup.find('tagName'):等同于soup.tagName

    print(soup.find('a'))
    
    
    '''
    微信
    '''

    属性定位:soup.find('tagName', 属性='')

    print(soup.find('div', class_='wrapper'))
    
    
    '''
    

    3.soup.find_all('tagName'):返回所有的标签,以列表的形式

    print(soup.find_all('a'))
    
    
    '''
    [微信, 知乎, 图片, 视频, 医疗, 汉语, 翻译, 问问, 百科, 地图, 更多, 知识, 应用, 全部, 无障碍, 企业推广, 免责声明, 意见反馈及投诉, 隐私政策, 网上有害信息举报专区, 京ICP证050897号, 京ICP备11001839号-1, 京公网安备11000002000025号, 搜狗输入法, 浏览器, 网址导航, 企业推广, 免责声明, 意见反馈及投诉, 隐私政策, 网上有害信息举报专区, 京ICP证050897号, 京ICP备11001839号-1, 京公网安备11000002000025号, , ]
    '''

    4.soup.select('某种选择器(id,class,标签......)'):返回一个列表

    print(soup.select('a'))
    
    '''
    [微信, 知乎, 图片, 视频, 医疗, 汉语, 翻译, 问问, 百科, 地图, 更多, 知识, 应用, 全部, 无障碍, 企业推广, 免责声明, 意见反馈及投诉, 隐私政策, 网上有害信息举报专区, 京ICP证050897号, 京ICP备11001839号-1, 京公网安备11000002000025号, 搜狗输入法, 浏览器, 网址导航, 企业推广, 免责声明, 意见反馈及投诉, 隐私政策, 网上有害信息举报专区, 京ICP证050897号, 京ICP备11001839号-1, 京公网安备11000002000025号, , ]
    '''
    print(soup.select('.user-box'))
    
    '''
    []
    '''

    5.soup.select('... > ... > ...'):层级选择

    print(soup.select('.wrapper > .header > .top-nav > ul > li > a'))
    
    '''
    [微信, 知乎, 图片, 视频, 医疗, 汉语, 翻译, 问问, 百科, 地图, 更多]
    '''

    爬虫正则+bs4+xpath+综合实战详解_第1张图片

    空格可以表示多层级,例如ul下的a标签全在li中,这时可以

    print(soup.select('.wrapper > .header > .top-nav > ul a'))
    
    '''
    [微信, 知乎, 图片, 视频, 医疗, 汉语, 翻译, 问问, 百科, 地图, 更多]
    '''

    6. .text/.string/.get_text:text和get_text是获取标签下所有的文本内容,可以跨层级

                                            string只能获取本标签中的文本内容

    爬虫正则+bs4+xpath+综合实战详解_第2张图片

    print(soup.select('.header')[0].text)
    
    
    '''
    
    
    
    网页
    微信
    知乎
    图片
    视频
    医疗
    汉语
    翻译
    问问
    百科
    地图
    
    更多
    知识应用全部
    ......
    '''
    
    print(soup.select('.header')[0].string)
    
    '''
    None
    '''

    7.['属性']:获取标签中的属性内容

    print(soup.select('.top-nav > ul > li > a')[0]['href'])
    
    '''
    http://weixin.sogou.com/
    '''

    bs4实战

    爬取三国演义中所有的章节标题和章节内容

    《三国演义》全集在线阅读_史书典籍_诗词名句网 (shicimingju.com)

    爬虫正则+bs4+xpath+综合实战详解_第3张图片

    由于是获取所有内容,因此不用一个个去p标签里面循环提取文字,而是之间用text或get_text

    import requests
    from bs4 import BeautifulSoup
    
    url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
    }
    
    page_text = requests.get(url, headers=headers).text
    soup = BeautifulSoup(page_text, 'lxml')
    li_list = soup.select('.book-mulu > ul > li')
    fp = open('sanguoyanyi.txt', 'w', encoding='utf-8')
    for li in li_list:
        title = li.a.string
        detail_url = 'https://www.shicimingju.com/' + li.a['href']
        # 对详情页发起请求
        detail_page_text = requests.get(detail_url, headers=headers).text
        detail_soup = BeautifulSoup(detail_page_text, 'lxml')
        div_tag = detail_soup.find('div', class_='chapter_content')
        content = div_tag.text
        fp.write(title + ': ' + content + '\n')
        print(title + '爬取成功\n')

    报错是因为现在这个网站对文字加密了,找不到chapter_content和p的内容,但代码是没问题的

    xpath

    最常用、编写最高效、最通用的数据解析方式

    原理:1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中
               2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获

    如何实例化一个etree对象:from Lxml import etree
            - 1.将本地的html文档中的源码数据加载到etree对象中:

                       etree.parse(filePath)
            - 2.可以将从互联网上获取的源码数据加载到该对象中:

                       etree.HTML('page_text' )

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('/html/head/meta')
    print(trs)
    
    '''
    [, , , , , , ]
    '''

    返回一个列表,里面放着Element类型的对象;/表示从根节点开始定位,表示一个层级

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('/html//meta')
    print(trs)
    
    '''
    [, , , , , , ]
    '''

    //表示多个层级,类似于bs4中的空格

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//meta')
    print(trs)
    
    '''
    [, , , , , , ]
    '''

    //也表示从任意层级开始匹配,可以获取全部的标签

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//div[@class="content"]')
    print(trs)
    
    '''
    []
    '''

    [@...]属性定位

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//div[@class="top-nav"]/ul/li')
    print(trs)
    
    '''
    [, , , , , , , , , , , ]
    '''
    
    trs = tree.xpath('//div[@class="top-nav"]/ul/li[1]')
    print(trs)
    
    '''
    []
    '''

    [num]索引定位,num不是下标,而是索引偏移量,因此1就是第1个

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//div[@class="top-nav"]/ul/li[2]/a/text()')
    print(trs)
    
    '''
    ['微信']
    '''

    爬虫正则+bs4+xpath+综合实战详解_第4张图片

    /text():只取本标签中的文字内容

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//div[@class="top-nav"]//text()')
    print(trs)
    
    '''
    ['\r\n            ', '\r\n                ', '网页', '\r\n                ', '微信', '\r\n                ', '知乎', '\r\n                ', '图片', '\r\n                ', '视频', '\r\n                ', '医疗', '\r\n                ', '汉语', '\r\n                ', '翻译', '\r\n                ', '问问', '\r\n                ', '百科', '\r\n                ', '地图', '\r\n                ', '\r\n                ', '更多', '\r\n                    ', '知识', '应用', '全部', '\r\n                ', '\r\n            ', '\r\n        ']
    '''

    //text():可以取到非直系的文字内容

    from lxml import etree
    
    # 实例化一个etree对象
    tree = etree.parse('sogou.html', etree.HTMLParser())
    # 层级关系,由外到内
    trs = tree.xpath('//div[@class="top-nav"]//@href')
    print(trs)
    
    '''
    ['http://weixin.sogou.com/', 'http://zhihu.sogou.com/', 'http://pic.sogou.com', 'https://v.sogou.com/', 'http://mingyi.sogou.com?fr=common_index_nav', 'http://hanyu.sogou.com?fr=pcweb_index_nav', 'http://fanyi.sogou.com?fr=common_index_nav_pc', 'https://wenwen.sogou.com/?ch=websearch', 'http://baike.sogou.com/Home.v', 'http://map.sogou.com', 'javascript:void(0);', 'http://zhishi.sogou.com', 'http://as.sogou.com/', 'http://www.sogou.com/docs/more.htm?v=1']
    '''

    /@属性:获取标签中属性的值

    58二手房房源

    爬取并解析出二手房房源的名称

    北京二手房网,北京房产网,北京二手房买卖出售交易信息-北京58同城

    爬虫正则+bs4+xpath+综合实战详解_第5张图片

    import requests
    from lxml import etree
    
    url = 'https://bj.58.com/ershoufang'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
    }
    page_text = requests.get(url, headers=headers).text
    tree = etree.HTML(page_text)
    trs = tree.xpath('//div[@class="property-content-title"]/h3/@title')
    
    fp = open('./2hand_house.txt', 'w', encoding='utf-8')
    for i in trs:
        fp.write(i + '\n')

    未完待续...

你可能感兴趣的:(爬虫)