[爬虫--字体反爬] 爬取起点小说中文网的字数

查看 95|回复 0
作者:hybpjx   
字体加密
主要 难点为 字体TTF加密 需要 下载相应的包 然后做解析 对应的月票也是同理
其实非常简单
详细的教程直接看我的博客 https://www.cnblogs.com/zichliang/p/17408064.html
里面有详细的解释
下文直接贴代码
!!本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
下面贴上代码
# -*- coding: utf-8 -*-

# @Time    : 2022/6/30 11:21

# @Author  : lzc

# @Email   : [email protected]

# @File    : QiDianNovelPro.py

# @Software: PyCharm

[color=]import
os
[color=]import
random
[color=]import
re
[color=]import
time
[color=]from
urllib.parse
[color=]import
urljoin
[color=]from
fontTools.ttLib
[color=]import
TTFont
[color=]import
fake_useragent
[color=]import
requests
[color=]from
lxml
[color=]import
etree
[color=]class
QiDianNovel:
   
[color=]def
[color=]__init__
(
[color=]self
):
        
[color=]self
.base_url =
[color=]"https://www.qidian.com/all/"

[color=]        
[color=]self
.session = requests.Session()
        
[color=]self
.item = {}
        
[color=]self
.header = {
            
[color=]"User-Agent"
: fake_useragent.UserAgent().random
        }
        
[color=]self
.font_dir_name =
[color=]"font"

[color=]        
[color=]self
.fontSep = os.sep
   
[color=]def
[color=]fetch
(
[color=]self
[color=],
url):
        response =
[color=]self
.session.get(url
[color=],
[color=]headers
=
[color=]self
.header)
        
[color=]return
response
   
[color=]def
[color=]parse_font
(
[color=]self
[color=],
html):
        
#
获得加密后的数字

        
encrypted_number = re.findall(
[color=]'
(.*?)
[color=]'
[color=],
html)
        
# print(encrypted_number)

        #
利用正则获取动态
url

        
font_url = re.findall(
[color=]r"
format\('eot'\); src: url\('(.*?)'\) format\('woff'\)
[color=]"
[color=],
html)[
[color=]0
]
        
#
发送请求,下载字体加密文件

        
font_response =
[color=]self
.fetch(font_url)
        jiami_font_file_name =
[color=]self
.font_dir_name +
[color=]self
.fontSep +
[color=]"jiami.woff"

[color=]        
# xml
解密的格式

        
jiemi_font_file_name =
[color=]self
.font_dir_name +
[color=]self
.fontSep +
[color=]"jiemi.xml"

[color=]

[color=]        
[color=]if not
os.access(jiami_font_file_name
[color=],
os.F_OK):
            os.mkdir(
[color=]"."
+
[color=]self
.fontSep +
[color=]self
.font_dir_name)
        
[color=]with
[color=]open
(jiami_font_file_name
[color=],
[color=]'wb'
)
[color=]as
f:
            f.write(font_response.content)
        
#
解析字体解密文件 并且 创建
TTFont
对象

        
font_obj = TTFont(jiami_font_file_name)
        
#
转换成
xml
明文格式

        
font_obj.saveXML(jiemi_font_file_name)
        mapping_dict =
[color=]self
.font_encode(encrypted_number
[color=],
font_obj)
        
#
通过匹配
response
去掉特殊符号的值 和 改成阿拉伯数字后的关系映射表,把密文改成明文
  100196   =

3

        
[color=]for
i
[color=]in
encrypted_number:  
#
去掉
response
去掉特殊符号的值
[[],[],[]]

            # print(i)  #  ['100388', '100389', '100388', '100385', '100385']

            
[color=]for
index
[color=],
num
[color=]in
[color=]enumerate
(i):  
# 100388

                # print(index,num)

               
[color=]for
k
[color=]in
mapping_dict:  
#
改成阿拉伯数字后的关系映射表

                    
# print(k)

                    
[color=]if
num ==
[color=]str
(k):
                        i[index] = mapping_dict[k]
        
# print("
解析之后的月票数
", encrypted_number)

        #
对单个明文进行拼接成完整的月票数

        
list_ = []
        
[color=]for
i
[color=]in
encrypted_number:
            j =
[color=]''

[color=]            
[color=]for
k
[color=]in
i:
                j += k
            list_.append(j)
        
[color=]return
list_
   
[color=]def
[color=]font_encode
(
[color=]self
[color=],
encrypted_number
[color=],
font_obj):
        """
        :param encrypted_number: 加密后的数字
        :param font_obj: fontTools对象
        :return:
        """
        
#
获取映射表

        
mapping_dict = font_obj.getBestCmap()
        
# print("
字体加密映射表
", mapping_dict)

        
[color=]for
index
[color=],
i
[color=]in
[color=]enumerate
(encrypted_number):
            new_font_list = re.findall(
[color=]r'
\d+
[color=]'
[color=],
i)  
#
去掉特殊符号
&#  & ;

            
encrypted_number[index] = new_font_list
        dict_e_a = {
            
[color=]"one"
:
[color=]'1'
[color=],
[color=]"two"
:
[color=]'2'
[color=],

[color=]            
[color=]"three"
:
[color=]'3'
[color=],
[color=]"four"
:
[color=]'4'
[color=],

[color=]            
[color=]"five"
:
[color=]"5"
[color=],
[color=]"six"
:
[color=]'6'
[color=],

[color=]            
[color=]"seven"
:
[color=]"7"
[color=],
[color=]"eight"
:
[color=]'8'
[color=],

[color=]            
[color=]"nine"
:
[color=]'9'
[color=],

[color=]            
[color=]"zero"
:
[color=]'0'
[color=],
[color=]'period'
:
[color=]"."

[color=]        
}
        
[color=]for
i
[color=]in
mapping_dict:
            
#
遍历
dict_e_a

            # print(i)

            
[color=]for
j
[color=]in
dict_e_a:
               
# dict_
的值等于
dict_e_a
的键

               
[color=]if
mapping_dict == j:
                    mapping_dict = dict_e_a[j]
        
# print("
替换成数字后的关系映射表
", mapping_dict)

        
[color=]return
mapping_dict
   
[color=]def
[color=]get_data
(
[color=]self
):
        
#
解析
url

        
html =
[color=]self
.fetch(
[color=]self
.base_url).text
        
# tree
对象 不解释

        
#
拿到 字体列表

        
font_list =
[color=]self
.parse_font(html)
        
[color=]for
index
[color=],
font
[color=]in
(
[color=]enumerate
(font_list)):
            
#
小说 字数

            
[color=]self
.item[
[color=]'novel_number'
] = font +
[color=]"
[color=]万字
[color=]"

[color=]            
#
防止反爬,随即休眠
1

2


            
time.sleep(random.randint(
[color=]1
[color=],
[color=]2
))
            
[color=]print
(
[color=]self
.item)
[color=]if
__name__ ==
[color=]'__main__'
:
    QiDianNovel().get_data()

字体, 明文

您需要登录后才可以回帖 登录 | 立即注册