• 聚焦爬虫之正则解析


    一、聚焦爬虫:

      如果想要爬取页面中指定的内容,就要用到聚焦爬虫, 必须建立在通用爬虫的基础上

    二、聚焦爬虫的编码流程:

      指定URL

      发送请求

      获取响应数据

      数据解析

      持久化存储

    如何实现数据解析:

      正则解析(1个案例)

      bs4(BeautifulSoup4)解析(1个案例)

      xpath解析(通用性比较强, 3个案例)

    数据解析的原理:

      进行标签的定位

      通过定位到的标签进行取文本和取属性

    五、代码实现——正则解析

    1、如何用爬虫程序下载一张图片

    # 如何用爬虫程序下载一张图片
    import requests
    
    img_url = "http://www.521609.com/uploads/allimg/140717/1-140GF92503-lp.jpg"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    
    response = requests.get(url=img_url, headers=headers)
    
    img_data = response.content  # 如果下载的是图片,视频或其他文件的数据,统一都为二进制数据,需要用到response.content来获取
    
    with open("./meinv.jpg", 'wb') as f:
        f.write(img_data)

    2、使用urllib模块下载图片(代码非常简洁)

    # 使用urllib模块下载图片(代码非常简洁)
    # 有一个缺陷,就是没有实现UA伪装,如果遇到有UA检测的网站的话,还是得换回requests模块
    from urllib import request
    
    url = "http://www.521609.com/uploads/allimg/140717/1-140GF92626-lp.jpg"
    
    request.urlretrieve(url=url, filename="./qingmeizi.jpg")

    3、爬取并下载校花网里面美女校花版块里面的图片

    # 案例: 爬取并下载校花网里面美女校花版块里面的图片
    import re
    import os
    import requests
    from urllib import request
    
    # 1. 指定URL
    url = "http://www.521609.com/meinvxiaohua/"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    ex = '<li><a href=.*?<img src="(.*?)" width="160" height="220".*?</a></li>'
    
    # 创建一个存放图片的目录
    if not os.path.exists('./meinv'):
        os.mkdir('./meinv')
    
    # 2. 发送请求
    response = requests.get(url=url, headers=headers)
    
    # 3. 获取页面源码数据
    page_text = response.text
    
    # 4. 数据解析(先要去网页上去分析页面源码里面的标签)
    url_list = re.findall(ex, page_text, re.S)
    print(url_list)
    
    # 5. 持久化存储
    for url in url_list:
        img_url = "http://www.521609.com" + url
        img_name = url.split("/")[-1]
        img_path = "./meinv/" + img_name  # ./meinv/10642054117-1.jpg
        
        # 使用urllib模块下载图片
        request.urlretrieve(img_url, img_path)
        print("{img_name}图片下载完成".format(img_name=img_name))

    注解:re.S:单行匹配

    # re.S :单行匹配
    import re
    
    html = """<li><a href="/meinvxiaohua/1987.html"><img src="/uploads/allimg/090616/10642054117-1.jpg" width="160" height="220" border="0" alt="东莞理工学院城市学院2009"></a><br>
                    <a href="/meinvxiaohua/1987.html" class="title">东莞理工学院城市学院2009</a></li>"""
    
    ex = '<li><a href=.*?<img src="(.*?)" width="160" height="220".*?</a></li>'
    
    url = re.findall(ex, html, re.S)[0]
    print(url)

    六、代码实现——bs4解析

    bs4解析

    • bs4的安装

      • pip3 install bs4
      • pip3 install lxml
    • bs4的使用:

      • from bs4 import BeautifulSoup
    • bs4的解析原理:

        1. 实例化一个BeautifulSoup对象,将页面源码数据加载到该对象中
        1. 使用该对象中的相关方法,进行标签内的文本和属性的提取
    • bs4的使用方法:

      • 本地加载
        • f = open("./meinv.jpg", 'rb')
        • soup = BeautifulSoup(f, 'lxml') # 第一个参数是文件句柄
      • 网络加载
        • page_text = requests.get(url=url).text
        • soup = BeautifulSoup(page_text, 'lxml')
    • soup对象的相关方法: (1)根据标签名查找

        - soup.a   获取页面源码中第一个符合要求的标签

      (2)获取属性, 返回的永远是一个单数

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

      (3)获取文本内容

        - soup.string: 只可以获取直系标签中的文本内容
        - soup.text: 获取标签下的所有文本内容
        - soup.get_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 > p > a > .lala          只能是下面一级
            - 多层级: div .tang a  下面好多级

      【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

    例如:

    from bs4 import BeautifulSoup
    
    # 1 读取本地文件的文件句柄
    f = open('./test_page.html', 'r', encoding='utf-8')
    
    # 2 实例化一个BeautifulSoup对象
    soup = BeautifulSoup(f, 'lxml')
    print(soup)

    soup.a
    soup.div
    soup.a.attrs.get("title")
    soup.a.get("href")

     七、代码实现——xpath解析

    xpath解析

    • 特点:

      • 通用性非常强
    • 安装:

      • pip3 install lxml
    • 导包:

      • from lxml import etree
    • xpath的解析原理

        1. 实例化一个etree对象, 将页面源码加载到该对象中
        1. 使用该对象中的xpath方法结合着xpath表达式进行标签的文本和属性的提取
    • 实例化对象的方法:

      • 本地加载:
        • tree = etree.parse("./test_page.html")
        • tree.xpath('xpath表达式') # 注意这里最好是使用单引号,不解释, 一会就明白
      • 网络加载:
        • tree = etree.HTML(page_text)
        • tree.xpath('xpath表达式')
    • xpath表达式 /: 从标签开始实现层级定位 //: 从任意位置实现标签的定位

      属性定位:

        语法: tag[@attrName="attrValue"]
        //div[@class="song"]  # 找到class属性值为song的div标签

      层级&索引定位:

        # 注意索引值是从1开始
        //div[@class="tang"]/ul/li[2]/a  # 找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a

      逻辑运算:

        //a[@href="" and @class="du"]  # 找到href属性值为空且class属性值为du的a标签

      模糊匹配:

        //div[contains(@class, "ng")]
        //div[starts-with(@class, "ta")]

      取文本:

        //div[@class="song"]/p[1]/text()  # 取直系文本内容
        //div[@class="tang"]//text()  # 取所有文本内容

      取属性:

        //div[@class="tang"]//li[2]/a/@href

    1、爬取58二手房的房源信息(列表页爬取标题和价格, 详情页爬取概况)

    # 需求: 爬取58二手房的房源信息(列表页爬取标题和价格, 详情页爬取概况)
    import requests
    from lxml import etree
    from decode_handler import get_crack_text, base64_code
    
    url = "https://sz.58.com/ershoufang/?PGTID=0d100000-0000-43ff-252a-3c9a606fba70&ClickID=2"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    
    # 获取页面源码数据
    page_text = requests.get(url=url, headers=headers).text
    
    # 实例化etree对象,进行数据解析
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
    
    all_data_list = list()
    for li in li_list:
        title = li.xpath('./div[2]/h2/a/text()')[0]  # ./表示的就是我的当前标签(li标签)
        price_list = li.xpath('./div[3]//text()')
        price = "".join(price_list)
        detail_url = li.xpath('./div[2]/h2/a/@href')[0]
    
        # 向详情页的URL发送请求,获取详情页的概况数据
        detail_page_text = requests.get(url=detail_url, headers=headers).text
        
        # 再新实例化一个详情页的etree对象,进行详情页的数据解析
        detail_tree = etree.HTML(detail_page_text)
        desc = "".join(detail_tree.xpath('//div[@id="generalSituation"]/div//text()'))
        
        dic = {
            "title": title,
            "price": price,
            "desc": desc
        }
        all_data_list.append(dic)
    
    print(all_data_list)
    # 解析出所有城市名称https://www.aqistudy.cn/historydata/
    
    tree.xpath('//div[@]/li/a/text() | //div[@]/ul/div[2]/li/a/text()')

    八、作业

    1、爬取贝壳网二手房源

    # 需求:爬取贝壳网二手房源
    import requests
    from lxml import etree
    
    url = "https://sz.ke.com/api/newhouserecommend?type=1&query=https%3A%2F%2Fsz.ke.com%2Fershoufang%2F"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    
    # 获取页面源码数据
    page_text = requests.get(url=url,headers=headers).text
    
    # 实例化etree对象,进行数据解析
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@class="sellListContent"]/li')
    print(li_list)
    
    all_data_list=list()
    for li in li_list:
        title=li.xpath('./div/div/a/@title')[0]
        print(title)
        price=li.xpath('./div/div[2]/div[5]/div//@title')[0]
        print(price)
        datail_url=li.xpath('./a/@href')[0]
        print(datail_url)
        
        # 向详情页的url发送请求,获取详情页的概况数据
        detail_page_text = requests.get(url=detail_url,headers=headers).text
        
        # 再实例化一个详情页的etree对象,进行详情页的数据解析
        detail_tree = etree.HTML(detail_page_text)
        desc = "".join(detail_tree.xpath('//div[@class="content"]ul/li//text()'))
        
        dic = {
            "title": title,
            "price": price,
            "desc": desc
        }
        all_data_list.append(dic)
        
    print(all_data_list)    

    2、获取彼岸汽车4K图片

    # 获取彼岸汽车4K图片
    import requests
    from lxml import etree
    import os
    
    url="http://pic.netbian.com/4kqiche/"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    if not os.path.exists("./qiche/"):
        os.mkdir("./qiche/")
    
    # 获取页面源码数据
    page_text=requests.get(url=url,headers=headers).text
    
    # 实例化etree对象,进行数据解析
    tree = etree.HTML(page_text)
    li_list=tree.xpath('//ul[@class="clearfix"]/li')  # li标签的对象
    
    
    print(li_list)
    
    
    for li in li_list:
        img_url="http://pic.netbian.com" + li.xpath('./a/img/@src')[0]
        img_name=li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk')  # 处理编码
        
        print(img_name)
        
        # 向详情页的URL发送请求,获取详情页的图片数据
        img_page=requests.get(url=img_url,headers=headers).content
        
        with open('./qiche/'+img_name+'.jpg','wb') as f:
            f.write(img_page)

     3、爬取百度贴吧的评论内容

    # 爬取百度贴吧的评论内容
    import requests
    from lxml import etree
    
    url = "https://tieba.baidu.com/p/5126900475"
    comment_url = "https://tieba.baidu.com/p/totalComment?t=1578445848467&tid=6320163250&fid=59099&pn=1&see_lz=0"
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    
    page_text = requests.get(url=url, headers=headers).text
    
    tree = etree.HTML(page_text)
    div_list = tree.xpath('//div[@class="l_post l_post_bright j_l_post clearfix  "]')
    
    all_data_list = list()
    for div in div_list:
        desc = div.xpath('./div[2]/div[1]/cc/div[2]//text()')
        all_data_list.append("".join(desc).strip())
    
    print(all_data_list)

    4、爬取http://pic.netbian.com/4kqiche/上面的汽车图片和标题

    import requests
    from lxml import etree
    
    url = "http://pic.netbian.com/4kqiche/"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    }
    
    response = requests.get(url=url, headers=headers)
    # response.encoding = "utf-8"  # 对响应对象进行编码处理
    
    page_text = response.text
    
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@class="clearfix"]/li')
    
    for li in li_list:
        img_url = "http://pic.netbian.com" + li.xpath('./a/img/@src')[0]
        title = li.xpath('./a/b/text()')[0]
        title = title.encode("iso-8859-1").decode("gbk") # 如果针对响应对象处理编码不成功的话,需要针对出现乱码的数据单独进行编码处理
        
        print(img_url, title)
  • 相关阅读:
    代码可复用性
    开始读《道不远人深入解析ASP.NET 2.0控件开发>>
    我的软件通讯录之二
    .Net中的堆于栈
    JavaScript技巧
    我的软件之通讯录(C#)
    快过年了,自己却病了,哎~~~~~~~
    整合dz论坛短消息出现的问题
    [转]用反射+特性列出所有的枚举变量及其描述信息,绑定到DropDownList上。
    [转]Javascript 调用MSAgent(Desc:网页中出现魔法巫师)
  • 原文地址:https://www.cnblogs.com/youhongliang/p/12694573.html
Copyright © 2020-2023  润新知