Skip to content

Latest commit

 

History

History
333 lines (267 loc) · 20.7 KB

573-253240-爬取图像数据_汉字源_甲骨文文字.sy.md

File metadata and controls

333 lines (267 loc) · 20.7 KB
show version enable_checker
step
1.0
true

爬取图片数据

回忆

  • 上次爬了纸飞机的网站
  • 从首页爬到内容页
  • 从内容页第一个示例图开始
  • 一个个地遍历
  • 经过二重循环完成任务
  • 到最后才发现图像的普遍性规律
  • 不过有的网站中的图片是嵌入到网页中的
  • 这种情况怎么办呢?🤔

举个例子

图片描述

  • img 元素的 src 属性
  • div 元素的 style 属性中的 background-image 属性
    • url 后面所跟的图片来自于 data
    • 这些图片怎么能就直接写在网页里面呢?

rfc2397

  • 这种写法最初的征求意见稿来自于 rfc2397

图片描述

  • 那么,什么是 rfc 呢?

从 ID 到 RFC

  • Internet 技术管理的核心是制定网络连接和应用的协议标准。在 Internet 上,任何一个用户都可以对 Internet 某一领域的问题提出自己的解决方案或规范,作为 Internet 草案(ID,Internet Drafts)提交给 IETF。
    • 草案存放在美国、欧洲和亚太地区的工作文件站点上,供世界多国自愿参加的 IETF 成员进行讨论、测试和审查。最后由 IESG 确定该草案是否能成为 Internet 的标准。
  • RFC 文档也称请求审议文档(Requests for Comments,RFC),是一系列不断修改和完善的报告、协议提案和协议标准,是用于发布 Internet 标准的一种网络文件或工作报告,篇幅从 1 页到数百页不等。
    • RFC 文档必须被分配 RFC 编号后才能在网络上发布。例如,RFC 2401 的内容是有关 Internet 协议的安全体系结构。
    • 如果一个提议规范进行了修改,并且对 Internet 草案进行了重写和升级,则在发布时将获得一个新的 RFC 编号(该编号的数字大于原来的编号)。
    • 因此,通过 RFC 编号,人们可以确定哪些是最新的文档。
  • 就算可以把图片数据直接写在网页里,这么做有什么好处呢?

图片 data 数据的优缺点

  • 这样做的好处是:
    • 节省了一个 http 请求
    • 原来浏览器读到 img 的时候
    • 需要给图片地址再发个请求
    • 这样就要再去请求得到图片的地址
  • 这样做的坏处:
    • 浏览器不会缓存图片的数据
    • 每次都要真的请求
    • 不会从缓存中读取数据
    • 而且一般来说写在 data 中的数据量稍微大些

编码方式

  • 为什么会变大呢?
  • Base64 是网络上最常见的用于传输 8Bit 字节代码的编码方式之一,大家可以查看 RFC2045 ~ RFC2049,上面有 MIME 的详细规范
  • Base64 编码可用于在 HTTP 环境下传递较长的标识信息
  • Base64 要求把每三个 8Bit 的字节转换为四个 6Bit 的字节(3 * 8 = 4 * 6 = 24)
  • 然后把 6Bit 再添两位高位 0,组成四个 8Bit 的字节
  • 也就是说,转换后的字符串理论上将要比原来的长 1/3
  • 这里说的是把原始信息转化为 base64 之后会增长
  • 不过原始信息格式也很多啊

各种格式

  • data:,文本数据
  • data:text/plain,文本数据
  • data:text/html,HTML 代码
  • data:text/html;base64,base64 编码的 HTML 代码
  • data:text/css,CSS 代码
  • data:text/css;base64,base64 编码的 CSS 代码
  • data:text/javascript,Javascript 代码
  • data:text/javascript;base64,base64 编码的 Javascript 代码
  • data:image/gif;base64,base64 编码的 gif 图片数据
  • data:image/png;base64,base64 编码的 png 图片数据
  • data:image/jpeg;base64,base64 编码的 jpeg 图片数据
  • data:image/x-icon;base64,base64 编码的 icon 图片数据
  • 真的有网站用这种 data 格式存储照片么?

照片存储

图片描述

  • 这个网站叫做汉字源
  • 是汉字叔叔做的
  • 不过现在日期停留在 2017
  • 我们去观察一下 robots.txt

robots.txt

图片描述

  • 并没有禁止什么
  • 那么我们可以走起来了

爬一个汉字

图片描述

  • 这是一个 Post 请求
  • 而不是我们以前见到的 Get 请求

图片描述

  • 而且特别不起眼的是消息头里面多了两个 key-value 对
    • Chinese
    • Seal
  • Chinese
    • 应该是所请求的文字的 unicode 编码对应的十进制形式
  • Seal
    • 不随请求文字变化而变化
    • 可以看做是固定值

构造请求的细节

from requests import post
from lxml import etree
import os
import time
char = 0x4e00
print(char)
url = "https://hanziyuan.net/etymology"
data = {
        "chinese": chr(char),
        "Bronze": "CfDJ8J6z8luTOtZGq022DWMpS8797u7UDVKSjSpbmdg-dyOCD88NgYd5tPIVv0KVNMh2sz1e_3xpmaXZCvl7pWgwiFOtY03F6TIUUh_dQ6d9NOF77qrA2Rt1eDdCKl5FraMguKOKMmUuWI-wg-hmbU1chKg"
        }
headers = {
        "Host": "hanziyuan.net",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0",
        "Accept": "text/html, */*; q=0.01",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Chinese": "26377",
        "Seal": "CfDJ8J6z8luTOtZGq022DWMpS8797u7UDVKSjSpbmdg-dyOCD88NgYd5tPIVv0KVNMh2sz1e_3xpmaXZCvl7pWgwiFOtY03F6TIUUh_dQ6d9NOF77qrA2Rt1eDdCKl5FraMguKOKMmUuWI-wg-hmbU1chKg",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Length": "180",
        "Origin": "https://hanziyuan.net",
        "Connection": "keep-alive",
        "Referer": "https://hanziyuan.net/",
        "Cookie": "Oracle=CfDJ8J6z8luTOtZGq022DWM...",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin"
        }
headers['Chinese'] = str(char)
response = post(url=url, data=data, headers=headers,)
print(response)
  • 这样确实可以得到响应
  • 得到了响应之后又该如何呢?

找到图片位置

图片描述

  • 这个图片其实是写在 css 的 background 中的
  • 而且用的就是 data 这种写法
  • 是把 svg+xml 文件转化为了 data 形式
  • 那我们首先要拿到 style 的位置

style

et_html = etree.HTML(response.content)
et_style = et_html.xpath("//body//style")
text = et_style[0].text
svglist = re.split("#\w{1,7}, #etymology\w{1,7} \{ background-image: url\(\'",text)
i = 0
html = ""
for svg in svglist:
    html += "<img src=\"" + svg + " \" />"
    i += 1
with open(chr(char),"wt") as f:
    f.write(html)
  • 找到 style 的位置然后把整个 style 文本进行切分
  • 切分为 svgdata 的 list
  • 然后对于每个 svgdata 写一个 img 元素
  • 追加进入这个文字对应的 html 文件中
  • 最后可对于每个确定的文字可以得到他的 html

循环遍历

import re,base64
from requests import post
from lxml import etree
import os
import time
for char in range(0x4e00,0x9FFF):
    try:
        print(char)
        url = "https://hanziyuan.net/etymology"
        data = {
                "chinese": chr(char),
                "Bronze": "CfDJ8J6z8luTOtZGq022DWMpS8797u7UDVKSjSpbmdg-dyOCD88NgYd5tPIVv0KVNMh2sz1e_3xpmaXZCvl7pWgwiFOtY03F6TIUUh_dQ6d9NOF77qrA2Rt1eDdCKl5FraMguKOKMmUuWI-wg-hmbU1chKg"
                }
        headers = {
                "Host": "hanziyuan.net",
                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0",
                "Accept": "text/html, */*; q=0.01",
                "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
                "Accept-Encoding": "gzip, deflate, br",
                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                "Chinese": "26377",
                "Seal": "CfDJ8J6z8luTOtZGq022DWMpS8797u7UDVKSjSpbmdg-dyOCD88NgYd5tPIVv0KVNMh2sz1e_3xpmaXZCvl7pWgwiFOtY03F6TIUUh_dQ6d9NOF77qrA2Rt1eDdCKl5FraMguKOKMmUuWI-wg-hmbU1chKg",
                "X-Requested-With": "XMLHttpRequest",
                "Content-Length": "180",
                "Origin": "https://hanziyuan.net",
                "Connection": "keep-alive",
                "Referer": "https://hanziyuan.net/",
                "Cookie": "Oracle=CfDJ8J6z8...",
                "Sec-Fetch-Dest": "empty",
                "Sec-Fetch-Mode": "cors",
                "Sec-Fetch-Site": "same-origin"
                }
        headers['Chinese'] = str(char)
        response = post(url=url, data=data, headers=headers,)
        print(response)
        et_html = etree.HTML(response.content)
        et_style = et_html.xpath("//body//style")
        text = et_style[0].text
        svglist = re.split("#\w{1,7}, #etymology\w{1,7} \{ background-image: url\(\'",text)
        i = 0
        html = ""
        #print(type(svglist),len(svglist))
        for svg in svglist:
            html += "<img src=\"" + svg + " \" />"
            i += 1
        with open(chr(char),"wt") as f:
            f.write(html)
        char += 1
    except:
        print("\033[41m[error]\033[0m char is " + str(char))

爬取结果

图片描述

  • 这确实可以爬取出来
  • 但是好像少了分类
  • 如果像原来那样有分类就更好了

图片描述

整存思路

  • 我要利用原来网页里的结构
  • 不要把他零碎取出来再组装
  • 我就直接把它取出来
  • 整体性地取出来

代码

import requests


inputchar = '收'


styss = '''
<link href="https://hanziyuan.net/css/bootstrap.min.css" rel="stylesheet"><link href="https://hanziyuan.net/css/bootstrap-theme.min.css" rel="stylesheet"><style>@-ms-viewport{width:device-width}@-o-viewport{width:device-width}@viewport{width:device-width}@keyframes ladda-spinner-line-fade{0%,to{opacity:.22}1%{opacity:1}}.ladda-button{position:relative}.ladda-button .ladda-spinner{position:absolute;z-index:2;display:inline-block;width:32px;top:50%;margin-top:0;opacity:0;pointer-events:none}.ladda-button .ladda-label{position:relative;z-index:3}.ladda-button .ladda-progress{position:absolute;width:0;height:100%;left:0;top:0;background:rgba(0,0,0,.2);display:none;transition:all .1s linear!important}.ladda-button[data-loading] .ladda-progress{display:block}.ladda-button,.ladda-button .ladda-label,.ladda-button .ladda-spinner{transition:all .3s cubic-bezier(.175,.885,.32,1.275)!important}.ladda-button[data-style=zoom-in],.ladda-button[data-style=zoom-in] .ladda-label,.ladda-button[data-style=zoom-in] .ladda-spinner,.ladda-button[data-style=zoom-out],.ladda-button[data-style=zoom-out] .ladda-label,.ladda-button[data-style=zoom-out] .ladda-spinner{transition:all .3s ease!important}.ladda-button[data-style=expand-right] .ladda-spinner{right:-6px}.ladda-button[data-style=expand-right][data-size=s] .ladda-spinner,.ladda-button[data-style=expand-right][data-size=xs] .ladda-spinner{right:-12px}.ladda-button[data-style=expand-right][data-loading]{padding-right:56px}.ladda-button[data-style=expand-right][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-right][data-loading][data-size=s],.ladda-button[data-style=expand-right][data-loading][data-size=xs]{padding-right:40px}.ladda-button[data-style=expand-left] .ladda-spinner{left:26px}.ladda-button[data-style=expand-left][data-size=s] .ladda-spinner,.ladda-button[data-style=expand-left][data-size=xs] .ladda-spinner{left:4px}.ladda-button[data-style=expand-left][data-loading]{padding-left:56px}.ladda-button[data-style=expand-left][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-left][data-loading][data-size=s],.ladda-button[data-style=expand-left][data-loading][data-size=xs]{padding-left:40px}.ladda-button[data-style=expand-up]{overflow:hidden}.ladda-button[data-style=expand-up] .ladda-spinner{top:-32px;left:50%;margin-left:0}.ladda-button[data-style=expand-up][data-loading]{padding-top:54px}.ladda-button[data-style=expand-up][data-loading] .ladda-spinner{opacity:1;top:26px;margin-top:0}.ladda-button[data-style=expand-up][data-loading][data-size=s],.ladda-button[data-style=expand-up][data-loading][data-size=xs]{padding-top:32px}.ladda-button[data-style=expand-up][data-loading][data-size=s] .ladda-spinner,.ladda-button[data-style=expand-up][data-loading][data-size=xs] .ladda-spinner{top:4px}.ladda-button[data-style=expand-down]{overflow:hidden}.ladda-button[data-style=expand-down] .ladda-spinner{top:62px;left:50%;margin-left:0}.ladda-button[data-style=expand-down][data-size=s] .ladda-spinner,.ladda-button[data-style=expand-down][data-size=xs] .ladda-spinner{top:40px}.ladda-button[data-style=expand-down][data-loading]{padding-bottom:54px}.ladda-button[data-style=expand-down][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-down][data-loading][data-size=s],.ladda-button[data-style=expand-down][data-loading][data-size=xs]{padding-bottom:32px}.ladda-button[data-style=slide-left]{overflow:hidden}.ladda-button[data-style=slide-left] .ladda-label{position:relative}.ladda-button[data-style=slide-left] .ladda-spinner{left:100%;margin-left:0}.ladda-button[data-style=slide-left][data-loading] .ladda-label{opacity:0;left:-100%}.ladda-button[data-style=slide-left][data-loading] .ladda-spinner{opacity:1;left:50%}.ladda-button[data-style=slide-right]{overflow:hidden}.ladda-button[data-style=slide-right] .ladda-label{position:relative}.ladda-button[data-style=slide-right] .ladda-spinner{right:100%;margin-left:0;left:16px}[dir=rtl] .ladda-button[data-style=slide-right] .ladda-spinner{right:auto}.ladda-button[data-style=slide-right][data-loading] .ladda-label{opacity:0;left:100%}.ladda-button[data-style=slide-right][data-loading] .ladda-spinner{opacity:1;left:50%}.ladda-button[data-style=slide-up]{overflow:hidden}.ladda-button[data-style=slide-up] .ladda-label{position:relative}.ladda-button[data-style=slide-up] .ladda-spinner{left:50%;margin-left:0;margin-top:1em}.ladda-button[data-style=slide-up][data-loading] .ladda-label{opacity:0;top:-1em}.ladda-button[data-style=slide-up][data-loading] .ladda-spinner{opacity:1;margin-top:0}.ladda-button[data-style=slide-down]{overflow:hidden}.ladda-button[data-style=slide-down] .ladda-label{position:relative}.ladda-button[data-style=slide-down] .ladda-spinner{left:50%;margin-left:0;margin-top:-2em}.ladda-button[data-style=slide-down][data-loading] .ladda-label{opacity:0;top:1em}.ladda-button[data-style=slide-down][data-loading] .ladda-spinner{opacity:1;margin-top:0}.ladda-button[data-style=zoom-out]{overflow:hidden}.ladda-button[data-style=zoom-out] .ladda-spinner{left:50%;margin-left:32px;transform:scale(2.5)}.ladda-button[data-style=zoom-out] .ladda-label{position:relative;display:inline-block}.ladda-button[data-style=zoom-out][data-loading] .ladda-label{opacity:0;transform:scale(.5)}.ladda-button[data-style=zoom-out][data-loading] .ladda-spinner{opacity:1;margin-left:0;transform:none}.ladda-button[data-style=zoom-in]{overflow:hidden}.ladda-button[data-style=zoom-in] .ladda-spinner{left:50%;margin-left:-16px;transform:scale(.2)}.ladda-button[data-style=zoom-in] .ladda-label{position:relative;display:inline-block}.ladda-button[data-style=zoom-in][data-loading] .ladda-label{opacity:0;transform:scale(2.2)}.ladda-button[data-style=zoom-in][data-loading] .ladda-spinner{opacity:1;margin-left:0;transform:none}.ladda-button[data-style=contract]{overflow:hidden;width:100px}.ladda-button[data-style=contract] .ladda-spinner{left:50%;margin-left:0}.ladda-button[data-style=contract][data-loading]{border-radius:50%;width:52px}.ladda-button[data-style=contract][data-loading] .ladda-label{opacity:0}.ladda-button[data-style=contract][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=contract-overlay]{overflow:hidden;width:100px;box-shadow:0 0 0 2000px transparent}.ladda-button[data-style=contract-overlay] .ladda-spinner{left:50%;margin-left:0}.ladda-button[data-style=contract-overlay][data-loading]{border-radius:50%;width:52px;box-shadow:0 0 0 2000px rgba(0,0,0,.8)}.ladda-button[data-style=contract-overlay][data-loading] .ladda-label{opacity:0}.ladda-button[data-style=contract-overlay][data-loading] .ladda-spinner{opacity:1}[dir=rtl] .ladda-spinner>div{left:25%!important}.navbar-collapse{overflow:hidden}body{position:relative;padding-top:50px}.row-eq-height{overflow:hidden}.row-eq-height [class*=col-]{margin-bottom:-99999px;padding-bottom:99999px}.pre-inline{white-space:pre-line}.m-0{margin:0}.p-0{padding:0}.mx-0{margin-left:0;margin-right:0}.my-1{margin-top:15px;margin-bottom:15px}.px-0{padding-right:0;padding-left:0}.p-1{padding:15px}.px-1{padding-right:15px;padding-left:15px}.py-1{padding-bottom:15px}.pt-1,.py-1{padding-top:15px}.pb-1{padding-bottom:15px}.bg-purple{background-color:#563d7c}.bg-black{background-color:#000}.border-purple{border-color:#563d7c}.border-top{border-top:1px solid}.text-black{color:#000}.text-lg{font-size:50px}.text-danger-color{color:#f44}a.text-danger-color,a.text-danger-color:visited{color:#f44!important}a.text-danger-color:active,a.text-danger-color:hover{color:#ff9c9c!important}.text-white{color:#eee}a.text-white,a.text-white:active,a.text-white:hover,a.text-white:visited{color:#fff!important}@media (min-width:768px) and (max-width:991px){.navbar-collapse.collapse{display:none!important}.navbar-collapse.collapse.in,.navbar-header .collapse,.navbar-toggle{display:block!important}.navbar-header{float:none}}.etymology-news .media-left a{width:50px;height:64px;display:block;font-size:40px;color:#e1bee7}.etymology-videos .media-left a{width:114px;height:64px;display:block;background-size:cover;background-repeat:no-repeat;background-position:50% 50%}.etymology-brand{padding-left:0;padding-right:0}@media (min-width:768px){.etymology-brand{padding-left:15px;padding-right:15px}}@media (max-width:351px){.etymology-nav-icon{display:none}}.navbar-fixed-top .navbar-collapse{max-height:none}.etymology-search button{margin-bottom:10px}.etymology-stat div{padding:5px}.etymology-stat h3{margin-top:10px}.etymology-alert a{margin:5px 0}.etymology-result ul{margin-top:15px}.etymology-result ul li div{background-color:#fff;width:105px;height:70px;background-size:60px 60px;background-position:50% 50%;background-repeat:no-repeat;color:transparent;cursor:pointer}.etymology-result ul li button{margin-top:5px;margin-bottom:15px;width:105px;font-weight:700}.etymology-research a{font-weight:700}.etymology-news .media-body{color:#ccc}.etymology-news .media-heading{color:#fff}.modal-dialog{width:auto;margin-left:15px;margin-right:15px}.modal-content,.modal-dialog{height:95%}.modal-content{background-size:contain;background-repeat:no-repeat;background-position:50%}.modal-body,.modal-footer,.modal-header{border:0 none}.modal-body{height:calc(100% - 120px)}</style>
'''

headers = {
    'Cookie': 'Oracle=CfDJ8J6z8...; Hm_lvt_44bf35035989ecd905587eb98a45525e=1635135381; Hm_lpvt_44bf35035989ecd905587eb98a45525e=1635135381; _ga=GA1.2.324463930.1635135381; _gid=GA1.2.537869903.1635135381',
    'Host': 'hanziyuan.net',
    'Origin': 'https://hanziyuan.net',
    'Referer': 'https://hanziyuan.net/',
    'Seal': 'CfDJ8J6z8luTOtZGq022DWMpS84Dbxx9YAbaEa87-Rk4j45RZtD1SMhhoZNcytqZXVG4EYBnX82ZnmulDMFwnL4qzb3euYEwfYBhi4_xvTX1FVFu_jL0IIqgnPhxPabW-spkhLDRJ81p0nlvV1XpYOrGc2M',
    'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
    'sec-ch-ua-mobile': '?0',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest'
}

data = {
    'chinese': inputchar,
    'Bronze': 'CfDJ8J6z8luTOtZGq022DWMpS84Dbxx9YAbaEa87-Rk4j45RZtD1SMhhoZNcytqZXVG4EYBnX82ZnmulDMFwnL4qzb3euYEwfYBhi4_xvTX1FVFu_jL0IIqgnPhxPabW-spkhLDRJ81p0nlvV1XpYOrGc2M'
}
url = 'https://hanziyuan.net/etymology'


headers['Chinese'] = str(ord(data['chinese']))
r = requests.post(url, data=data, headers=headers)

print(r.text, r.status_code)
print('---------------')


with open('test.html', 'w', encoding='utf-8')as f:
    f.write(styss+'\n')
    f.write(r.text)
print('---------------')

提取信息

  • 先把 head 里面的样式信息给都拿出来
  • 然后把 body 里的所有信息都拿出来
  • svg 的 data 就在 body 中的 style 里面

图片描述

  • 这样就把原来的网页结构拿到了

总结

  • 这次爬了汉字源
  • 图片不只是可以单独存在
  • 也可以嵌入到网页中的
  • 应该注意到请求头里面可以放东西
  • 爬取的时候可以利用原来网页整体的结构
  • 图片爬完了
  • 还能爬点什么呢?🤔
  • 下次再说