Python网络爬虫基础进阶到实战教程

news2024/9/21 16:39:42

文章目录

  • 认识网络爬虫
  • HTML页面组成
  • Requests模块get请求与实战
      • 效果图
      • 代码解析
  • Post请求与实战
        • 代码解析
      • 发送JSON格式的POST请求
      • 使用代理服务器发送POST请求
      • 发送带文件的POST请求
  • Xpath解析
        • XPath语法的规则集:
        • XPath解析的代码案例及其详细讲解:
          • 使用XPath解析HTML文档
          • 使用XPath解析XML文档
          • 处理命名空间的XPath解析
  • BeautifulSoup详讲与实战
      • 创建BeautifulSoup对象
        • 遍历文档树
        • 搜索文档树
        • 获取节点属性和文本内容
      • BeautifulSoup 代码案例讲解。
        • 解析HTML文档并获取标题
      • 遍历文档树并获取所有段落内容
      • 使用CSS选择器搜索文档树
      • 使用正则表达式搜索文档树
      • 解析XML文档并获取节点信息
      • 修改节点属性
  • 正则表达式
      • 正则表达式知识点
      • 正则表达式案例
  • 正则表达式实战
  • 字体反爬
  • Scrapy入门
      • Scrapy实例
  • 完结

认识网络爬虫

在这里插入图片描述

网络爬虫是指一种程序自动获取网页信息的方式,它能够自动化地获取互联网上的数据。通过使用网络爬虫,我们可以方便地获取到网络上的各种数据,例如网页链接、文本、图片、音频、视频等等。

HTML页面组成

在这里插入图片描述

网页是由HTML标签和内容组成,HTML标签通过标签属性可以定位到需要的内容。网页中的样式由CSS控制,JavaScript可以实现网页动态效果。

HTML标签是一种用于构建Web页面的标记语言,它描述了页面的结构和元素。HTML标签通常包含一个起始标签和一个结束标签,例如<div></div>。HTML标签也可以包含属性,属性用于提供有关元素的额外信息。例如,<a>元素的href属性指定了链接目标的URL地址,而<img>元素的src属性指定了要显示的图像文件的URL地址。

CSS是一种用于控制Web页面样式的样式表语言,它可以为HTML元素提供样式和布局。通过CSS,我们可以控制文本的字体、颜色、大小和样式,以及元素的大小、位置、边框和背景等。

JavaScript是用于实现Web页面动态效果的一种编程语言,它可以实现网页上的各种交互效果,例如弹出窗口、表单验证、动画效果等。

Requests模块get请求与实战

在这里插入图片描述

Requests是Python中的HTTP库,提供了简洁易用的接口进行HTTP请求。其中,GET请求常用于获取静态网页信息。

我们通过requests.get()方法来发送一个GET请求.

import requests

url = 'https://www.baidu.com'
response = requests.get(url)
print(response.text)

效果图

在这里插入图片描述

代码解析

第一行导入了requests模块,第二行指定了要请求的URL地址,在本例中我们使用百度首页作为示例。第三行使用requests库的get()方法来获取该URL的响应对象。响应对象包含了服务器返回的所有信息,包括Header(头部)和Body(主体)两部分。其中Header包含了很多信息,如日期、内容类型、服务器版本等,而Body包含了页面HTML源代码等具体信息。

第四行使用print()函数打印出响应内容的文本形式。运行这段代码,我们就可以在终端中看到百度首页的HTML源代码。

在实际爬虫中,我们可以利用requests模块的一些属性或者方法来解析响应内容,提取需要的数据。例如,可以使用response.status_code属性来获取HTTP状态码,使用response.headers属性来获取HTTP头部信息等。此外,我们还可以使用response.json()方法来解析JSON格式的响应内容,使用response.content方法来获取字节形式的响应内容等。

Post请求与实战

POST请求与GET请求的区别在于,POST请求会将请求参数放在请求体中,而GET请求则将请求参数放在URL中。通常情况下,POST请求比GET请求更安全,因为它可以隐藏请求参数。

我们通过requests.post()方法来发送一个POST请求,下面是详细的代码分析:

import requests

url = 'http://xxxx.org/post'  # 这里使用xxxx.org来演示POST请求
data = {'key1': 'value1', 'key2': 'value2'}
response = requests.post(url, data=data)
print(response.text)

代码解析

第一行导入了requests模块,
第二行指定了要请求的URL地址 。
第三行定义了请求参数data,这个字典中包含了两个键值对,分别表示key1和key2这两个参数的值。第四行使用requests库的post()方法来发送POST请求并获取响应对象。

我们通过data参数将请求参数放在请求体中,这里使用了字典类型作为请求参数。第五行使用print()函数打印出响应内容的文本形式。运行这段代码,我们就可以在终端中看到xxxx.org返回的响应内容,其中包括了我们发送的请求参数。

在实际爬虫中,我们可以利用requests模块的一些属性或者方法来解析响应内容,提取需要的数据。

发送JSON格式的POST请求

import requests
import json

url = 'http://xxxx.org/post'  # 这里使用xxxx.org来演示POST请求
data = {'key1': 'value1', 'key2': 'value2'}
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(data), headers=headers)
print(response.text)

在这个案例中,我们将请求参数data转换成JSON格式,并使用headers来指定Content-Type为application/json。然后,我们通过requests库的post()方法来发送POST请求。

使用代理服务器发送POST请求

import requests

proxy = {
    'http': 'http://10.10.1.10:3128',
    'https': 'https://10.10.1.10:1080'
}
url = 'http://xxxx.org/post'  # 这里使用xxxx.org来演示POST请求
data = {'key1': 'value1', 'key2': 'value2'}
response = requests.post(url, data=data, proxies=proxy)
print(response.text)

在这个案例中,我们通过proxy字典来指定代理服务器的地址和端口号。然后,我们通过requests库的post()方法来发送POST请求。

发送带文件的POST请求

import requests

url = 'http://xxxx.org/post'  # 这里使用xxxx.org来演示POST请求
files = {'file': open('myfile.txt', 'rb')}
response = requests.post(url, files=files)
print(response.text)

在这个案例中,我们通过files参数来指定要上传的文件。
open()函数打开文件,第一个参数是文件名,第二个参数是打开方式(rb表示二进制只读模式)。然后,我们通过requests库的post()方法来发送POST请求。

Xpath解析

在这里插入图片描述

XPath是一种用于选择XML文档中某些部分的语言。在Python中,我们可以使用lxml库来解析XML文档并使用XPath进行选择。
XPath语法主要由路径表达式和基本表达式构成。其中,路径表达式用于选择节点或者节点集合,而基本表达式用于指定某个元素、属性或者其他内容。

XPath语法的规则集:

表达式描述
nodename选择所有名为nodename的元素
/从当前节点选取根节点
//从当前节点选取任意节点
.选择当前节点
选择当前节点的父节点
@选择属性
*匹配任何元素节点
[@attrib]选择具有给定属性的所有元素
[@attrib=‘value’]选择具有给定属性值的所有元素
tagname[text() = ‘text’]选择具有给定文本的所有tagname元素

XPath解析的代码案例及其详细讲解:

使用XPath解析HTML文档
from lxml import etree
import requests

url = 'https://www.baidu.com'
html = requests.get(url).text
selector = etree.HTML(html)
result = selector.xpath('//title/text()')
print(result[0])

案例中,我们首先发送了一个GET请求获取百度首页的HTML源代码。然后,我们使用lxml库中的etree模块来构建一个XPath解析器,并将HTML源代码传给它进行解析。接着,我们使用XPath表达式’//title/text()'来选择HTML文档中title标签的内容。最后,我们打印出XPath语句返回的结果。

使用XPath解析XML文档
from lxml import etree

xml = '''
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giammarco Tomaselli</author>
    <year>2010</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J.K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
</bookstore>
'''

selector = etree.XML(xml)
result = selector.xpath('//book[1]/title/text()')
print(result[0])

案例中,我们定义了一个XML字符串,并使用etree.XML()方法来创建一个XPath解析器。然后,我们使用XPath表达式’//book[1]/title/text()'来选择XML文档中第一个book元素的title元素的内容。最后,我们打印出XPath语句返回的结果。

处理命名空间的XPath解析
from lxml import etree

xml = '''
<ns:bookstore xmlns:ns="http://www.example.com">
  <ns:book category="cooking">
    <ns:title lang="en">Everyday Italian</ns:title>
    <ns:author>Giammarco Tomaselli</ns:author>
    <ns:year>2010</ns:year>
    <ns:price>30.00</ns:price>
  </ns:book>
  <ns:book category="children">
    <ns:title lang="en">Harry Potter</ns:title>
    <ns:author>J.K. Rowling</ns:author>
    <ns:year>2005</ns:year>
    <ns:price>29.99</ns:price>
  </ns:book>
</ns:bookstore>
'''

selector = etree.XML(xml)
ns = {'ns': 'http://www.example.com'}
result = selector.xpath('//ns:book[1]/ns:title/text()', namespaces=ns)
print(result[0])

案例中,我们定义了一个带有命名空间的XML字符串,并使用etree.XML()方法来创建一个XPath解析器。然后,我们通过传递一个namespaces参数来指定命名空间的前缀和URI。最后,我们使用XPath表达式’//ns:book[1]/ns:title/text()'来选择第一个book元素的title元素的内容。最后,我们打印出XPath语句返回的结果。

BeautifulSoup详讲与实战

BeautifulSoup是常用的Python第三方库,它提供了解析HTML和XML文档的函数和工具。使用BeautifulSoup可以方便地遍历和搜索文档树中的节点,获取节点属性和文本内容等信息

创建BeautifulSoup对象

首先我们需要导入BeautifulSoup模块:

from bs4 import BeautifulSoup

使用BeautifulSoup对HTML文档进行解析,可以通过以下两种方式:

(1) 传递一个HTML字符串作为参数:

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')

(2) 传递一个文件路径或文件对象作为参数:

with open('example.html', 'r') as f:
    soup = BeautifulSoup(f, 'html.parser')

遍历文档树

很多时候,我们需要遍历整个文档树来查找特定的节点,或者获取节点的属性和文本内容。BeautifulSoup提供了多种遍历文档树的方法,包括:

(1) .contents:返回一个包含所有子节点的列表。

for child in soup.body.contents:
    print(child)

(2) .children:返回一个包含所有子节点的迭代器。

for child in soup.body.children:
    print(child)

(3) .descendants:返回一个包含文档树中所有子孙节点的迭代器。

for element in soup.descendants:
    print(element)

(4) .parent:返回一个节点的父节点。

p = soup.body.p
print(p.parent)

(5) .parents:返回一个包含节点所有祖先节点的迭代器。

p = soup.body.p
for parent in p.parents:
    print(parent.name)

搜索文档树

搜索文档树是BeautifulSoup的另一个重点。BeautifulSoup提供了几个搜索方法

(1) .find_all():返回一个满足条件的节点列表。

soup.find_all('p', class_='para1')
soup.find_all('p', {'class': 'para1'}, string='第一段落')

(2) .find():返回第一个满足条件的节点。

soup.find('p', class_='para1')
soup.find('p', {'class': 'para1'}, string='第一段落')

(3) .select():使用CSS选择器语法返回满足条件的节点列表。

soup.select('p.para1')
soup.select('p[class="para1"]')

获取节点属性和文本内容

获取节点的属性和文本内容也是常用的操作。BeautifulSoup提供了下面这些方法:

(1) .get():获取节点的指定属性。

p = soup.find('p', class_='para1')
print(p.get('class'))

(2) .text:获取节点的文本内容。

p = soup.find('p', class_='para1')
print(p.text)

(3) .string:获取节点的文本内容(如果节点只有一个子节点且该子节点是字符串类型)。

p = soup.find('p', class_='para1')
print(p.string)

BeautifulSoup 代码案例讲解。

解析HTML文档并获取标题

from bs4 import BeautifulSoup
import requests

url = 'https://www.baidu.com'
html = requests.get(url).text
soup = BeautifulSoup(html, 'html.parser')
title = soup.title.string
print(title)

案例中,我们首先发送了一个GET请求获取百度首页的HTML源代码。然后,我们使用BeautifulSoup来创建一个HTML解析器,并将HTML源代码传给它进行解析。接着,我们通过soup.title.string获取HTML文档中title标签的内容,并打印出结果。

遍历文档树并获取所有段落内容

from bs4 import BeautifulSoup

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')
for p in soup.body.children:
    if p.name == 'p':
        print(p.string)

案例中,我们创建了一个HTML字符串,并使用BeautifulSoup来创建一个HTML解析器。然后,我们通过soup.body.children遍历整个文档树,查找所有的p标签,并打印出每个标签的文本内容。

使用CSS选择器搜索文档树

from bs4 import BeautifulSoup

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')
p_list = soup.select('p.para1')
for p in p_list:
    print(p.text)

案例中,我们创建了一个HTML字符串,并使用BeautifulSoup来创建一个HTML解析器。然后,我们使用CSS选择器’p.para1’搜索文档树,并获取所有满足条件的p标签。最后,我们遍历p列表,并打印出每个标签的文本内容。
好的,接下来我再给出三个代码案例。

使用正则表达式搜索文档树

import re
from bs4 import BeautifulSoup

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')
pattern = re.compile('^p.*?1$')  # 匹配所有以p开头并且以1结尾的类名
p_list = soup.find_all(class_=pattern)
for p in p_list:
    print(p.text)

案例中,我们使用了Python的re模块来创建了一个正则表达式pattern。然后,我们使用soup.find_all(class_=pattern)来搜索文档树,获取所有满足条件的标签,并遍历列表打印出每个标签的文本内容。

解析XML文档并获取节点信息

from bs4 import BeautifulSoup

xml_doc = """
<?xml version="1.0" encoding="UTF-8"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
</data>
"""

soup = BeautifulSoup(xml_doc, 'xml')
for country in soup.find_all('country'):
    print(country['name'])
    print(country.rank.text)
    print(country.year.text)
    print(country.gdppc.text)
    for neighbor in country.find_all('neighbor'):
        print(neighbor['name'], neighbor['direction'])

案例中,我们创建了一个XML字符串,并使用BeautifulSoup来创建一个XML解析器。然后,我们使用soup.find_all()方法搜索文档树,获取所有满足条件的标签,并遍历它们打印出相关信息。

修改节点属性

from bs4 import BeautifulSoup

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')
p = soup.find('p', class_='para1')
p['class'] = 'new_class'
print(p)

案例中,我们创建了一个HTML字符串,并使用BeautifulSoup来创建一个HTML解析器。然后,我们使用soup.find()方法搜索文档树,获取第一个满足条件的p标签。接着,我们通过p[‘class’]操作修改了标签的class属性,并打印出修改后的标签。

正则表达式

正则表达式知识点

正则表达式是一种用于匹配字符串的模式。它通过字符组成规则定义了搜索文本中特定模式的方法。Python中的re模块提供了使用正则表达式的功能。

常用的正则表达式元字符:

  • . 表示任意字符。
  • \d表示数字,\D表示非数字。
  • \w表示单词字符,即az、AZ、0~9和下划线。
  • \W表示非单词字符。
  • \s表示空白符,包括空格、制表符、换行符等。
  • \S表示非空白符。
  • ^表示匹配行首。
  • $表示匹配行尾。
  • *表示匹配前面的字符零次或多次。
  • +表示匹配前面的字符一次或多次。
  • ?表示匹配前面的字符零次或一次。
  • {m}表示匹配前面的字符m次。
  • {m,n}表示匹配前面的字符m到n次。
  • […]表示匹配方括号中任意一个字符。
  • [^…]表示匹配除了方括号中给出的字符以外的任意一个字符。
  • (…)表示匹配括号中的表达式。

re模块中常用的函数:

  • re.match():从字符串的开头开始匹配,只匹配一次。
  • re.search():在字符串中匹配第一个符合条件的内容。
  • re.findall():在字符串中匹配所有符合条件的内容并以列表的形式返回。
  • re.sub():用一个新的字符串替换掉匹配到的所有内容。
  • re.compile():将正则表达式转化为一个正则表达式对象,以便于复用。

正则表达式案例

(1) 匹配手机号码

import re

phone_nums = ['13912345678', '13812345678', '13512345678', '13612345678', '13712345678']

pattern = r'^1[3-9]\d{9}$'
for phone_num in phone_nums:
    if re.match(pattern, phone_num):
        print(f'{phone_num}是一个合法的手机号码')
    else:
        print(f'{phone_num}不是一个合法的手机号码')

代码演示了如何使用正则表达式匹配手机号码。
首先,我们定义了一个包含多个手机号码的列表,并创建了一个正则表达式对象pattern。该正则表达式匹配以1开头的11位数字字符串,其中第二位数字介于3和9之间。然后,我们使用re.match()方法对每个手机号码进行匹配,并打印结果。

(2) 替换HTML文档中的标签

import re

html_doc = """
<html>
<head><title>这是标题</title></head>
<body>
<p class="para1">第一段落</p>
<p class="para2">第二段落</p>
</body>
</html>
"""

pattern = r'<.*?>'
new_doc = re.sub(pattern, '', html_doc)
print(new_doc)

代码演示了如何使用正则表达式替换HTML文档中的标签。
首先,我们定义了一个包含HTML标签的字符串,并创建了一个正则表达式对象pattern。该正则表达式匹配任意HTML标签,并将其替换为空字符串。然后,我们使用re.sub()方法对HTML文档进行替换,并打印结果。

(3) 提取金融数据

import re

text = '2019年GDP增速为7.5%,同比增长0.3个百分点;CPI同比上涨2.5%,环比上涨0.3%。'

pattern1 = r'\d+.\d+%'
pattern2 = r'[A-Z]+'
num_list = re.findall(pattern1, text)
unit_list = re.findall(pattern2, text)
for i in range(len(num_list)):
    print(f'{num_list[i]} {unit_list[i]}')

代码演示了如何使用正则表达式提取金融数据。
首先,我们定义了一个包含金融数据的字符串,并创建了两个正则表达式对象pattern1和pattern2。其中,pattern1匹配百分数,pattern2匹配单位符号。然后,我们使用re.findall()方法分别提取百分数和单位符号,并以列表的形式返回。最后,我们使用for循环遍历两个列表,并将相同位置上的元素打印在一起。

正则表达式实战

代码是一个简单的Python脚本,可以用于统计某个文件夹下所有文本文件中各个单词的出现频率,并输出前十个出现频率最高的单词及其出现次数。在代码中,我们将使用正则表达式来去除标点符号、换行符等非单词字符,以便于单词的准确统计。

import os
import re
from collections import Counter

def get_word_counts(folder_path):
    """
    统计指定文件夹中所有文本文件中各个单词的出现频率,并返回一个Counter对象。
    """
    word_counter = Counter()

    for root, dirs, files in os.walk(folder_path):
        for file in files:
            if file.endswith('.txt'):
                file_path = os.path.join(root, file)

                # 读取文本文件内容
                with open(file_path, 'r', encoding='utf-8') as f:
                    text = f.read()

                    # 使用正则表达式去除标点符号、换行符等非单词字符
                    pattern = r'\b\w+\b'
                    words = re.findall(pattern, text)

                    # 对单词列表进行计数,并将结果更新到Counter对象中
                    word_counter.update(words)

    return word_counter

if __name__ == '__main__':
    folder_path = 'test'
    word_counter = get_word_counts(folder_path)

    # 输出前十个出现频率最高的单词及其出现次数
    top_n = 10
    print(f'Top {top_n} words:')
    for word, count in word_counter.most_common(top_n):
        print(f'{word:<10} {count}')

代码中的get_word_counts()函数用于统计指定文件夹中所有文本文件中各个单词的出现频率,并返回一个Counter对象。在函数中,我们使用了Python内置的oscollections模块,以便于对文件和单词计数进行操作。
os.walk()方法可以遍历指定文件夹下所有子文件夹中的文件,比如我们指定的folder_path文件夹。然后,我们对每个文本文件进行读取,并使用正则表达式去除标点符号、换行符等非单词字符,以便于单词的准确统计。最后,我们使用Counter对象来对单词列表进行计数,并将结果更新到该对象中。

在主程序中,我们调用get_word_counts()函数来获取单词计数结果,并输出前十个出现频率最高的单词及其出现次数。在这里,我们使用了most_common()方法来获取前N个出现频率最高的单词及其出现次数,并使用字符串格式化输出结果。

字体反爬

字体反爬是一种常见的网站反爬手段,即将大部分文本内容通过特定的字体进行加密混淆,以防止爬虫直接抓取数据。通常情况下,爬虫需要先解密字体,然后才能正常获取到文本内容。

常用的字体反爬解密方法有以下几种:

  1. 解析woff文件

很多网站会使用woff格式的字体文件来渲染文本内容,爬虫需要先下载这些字体文件,并解析出字符与字形之间的对应关系,然后才能正常解密文本内容。

  1. 使用fontTools库

Python中有一个非常优秀的字体解析库叫做fontTools,可以帮助我们轻松地解析字体文件,并生成字形对应表。使用该库可以避免自行解析字体文件所遇到的各种问题。

  1. 使用在线字体解密工具

有些网站提供了在线字体解密工具,如FontSpider、字体反爬插件等,可以帮助我们快速地解密字体。不过,使用这种方法需要注意隐私安全问题。

(1) 解析woff文件

import base64
from fontTools.ttLib import TTFont

# 下载字体文件并保存为base64编码字符串
font_url = 'http://example.com/font.woff'
font_base64 = '...'

# 将base64编码字符串解码并保存到本地
with open('font.woff', 'wb') as f:
    font_data = base64.b64decode(font_base64)
    f.write(font_data)

# 解析字体文件并获取字形对应表
font = TTFont('font.woff')
cmap = font.getBestCmap()

# 定义替换规则
replace_dict = {
    '&#x8FDE;': '0',
    '&#xE4CD;': '1',
    '&#xFAF5;': '2',
    '&#xEA72;': '3',
    '&#xEDB4;': '4',
    '&#xF640;': '5',
    '&#xF62F;': '6',
    '&#xEB10;': '7',
    '&#xF9D4;': '8',
    '&#xF15C;': '9',
}

# 替换文本内容
text = '&#xE4CD;&#xF15C;&#xF15C;'
for key, value in replace_dict.items():
    text = text.replace(key, value)

# 输出结果
print(text)

代码演示了如何解析woff文件,并使用字形对应表来解密文本内容。首先,我们将从网站上下载字体文件,并保存为base64编码字符串。然后,我们将该编码字符串解码并保存到本地。接下来,我们使用fontTools库读取字体文件,并获取其中的字形对应表。需要注意的是,不同字体文件对应的字形对应表可能不同,因此需要根据具体情况来确定使用哪个表。
我们定义了一个替换规则字典replace_dict,其中包含了从未解密的字符到明文字符的映射关系。最后,我们使用字符串的replace()方法将未解密的文本内容替换为明文,从而得到结果。

(2) 使用fontTools库

import requests
from io import BytesIO
from fontTools.ttLib import TTFont

# 下载字体文件并用fontTools库读取
font_url = 'http://example.com/font.woff'
font_data = requests.get(font_url).content
font = TTFont(BytesIO(font_data))

# 获取字形对应表
cmap = font.getBestCmap()

# 定义替换规则
replace_dict = {
    '&#x8FDE;': '0',
    '&#xE4CD;': '1',
    '&#xFAF5;': '2',
    '&#xEA72;': '3',
    '&#xEDB4;': '4',
    '&#xF640;': '5',
    '&#xF62F;': '6',
    '&#xEB10;': '7',
    '&#xF9D4;': '8',
    '&#xF15C;': '9',
}

# 解密文本内容
text = '&#xE4CD;&#xF15C;&#xF15C;'
for key, value in replace_dict.items():
    glyph_id = cmap[int(key[3:-1], 16)]
    text = text.replace(key, value)

# 输出结果
print(text)

代码演示了如何使用fontTools库解析字体文件,并生成字形对应表。首先,我们使用requests库从网站上下载字体文件,并使用BytesIO将字节流转换为文件。然后,我们使用fontTools库读取该文件,并获取其中的字形对应表。需要注意的是,通过这种方式获取到的字形对应表可能与其他方式获取到的表略有不同,因此需要进行实验来确定使用哪个表。
我们定义了一个替换规则字典replace_dict,并使用字符串的replace()方法将未解密的文本内容替换为明文,从而得到结果。

(3) 使用在线字体解密工具

import requests
from fontSpider import FontSpider

# 下载字体文件并保存为base64编码字符串
font_url = 'http://example.com/font.woff'
r = requests.get(font_url)
font_base64 = FontSpider(r.content).to_base64()

# 使用在线字体解密工具解密文本内容
text = '&#xE4CD;&#xF15C;&#xF15C;'
response = requests.post('http://font-spider.com/api/v1/decrypt', data={'font': font_base64, 'text': text})
result = response.json()

# 输出结果
print(result['data'])

代码演示了如何使用在线字体解密工具来解密文本内容。首先,我们从网站上下载字体文件,并使用FontSpider库将其转换为base64编码字符串。然后,我们使用requests库向在线字体解密工具发送POST请求,并将字体文件和未解密的文本内容作为参数传递。该工具会自动解密文本内容,并返回解密后的结果。最后,我们从响应结果中提取出解密后的文本内容,并输出结果。

需要注意的是,使用在线字体解密工具可能存在隐私安全问题,因此尽量避免在生产环境中使用。

Scrapy入门

Scrapy是一个基于Python的快速、高效的Web爬虫框架,可用于数据抓取、信息处理以及存储的开发。它是一个专业的爬虫框架,提供了许多必要的功能,如请求调度、数据解析,以及数据存储等。Scrapy可以自动下载网页,并提供了XPath以及CSS选择器等多种方法,支持多线程和分布式爬取,并可以通过插件扩展其功能。

  1. 工程结构

Scrapy的工程具有标准的项目结构,通常包含以下几个文件:

  • scrapy.cfg:Scrapy项目配置文件。
  • items.py:定义爬取的数据结构。
  • middlewares.py:管理请求和响应,例如User-Agent、代理等。
  • pipelines.py:配置到底怎么样后续处理item。
  • settings.py:保存爬虫的参数设置。
  • spiders/:保存爬虫代码的目录。
  1. 爬虫流程

Scrapy的爬虫流程如下:

  • 发起请求:通过定义好的URL地址来发送HTTP请求。
  • 下载页面:Scrapy会自动下载对应的页面,或使用第三方库,如requests、Selenium等。
  • 解析页面:使用XPath或CSS选择器解析网页内容。
  • 保存数据:将解析得到的数据保存到本地或数据库中。
  1. Scrapy组件

Scrapy具有以下几个重要组件:

  • Spider:定义如何抓取某个站点,包括如何跟进链接、如何分析页面内容等。
  • Item:定义爬取的数据结构。
  • Pipeline:负责处理Item,如清理、过滤、存储到数据库等。
  • Downloader:负责下载网页,并将结果传递给Spider。
  • Scheduler:负责调度Spider发起请求,并将结果传递给Downloader。

Scrapy实例

  1. 爬取豆瓣电影TOP250的数据
import scrapy

class DoubanMovieSpider(scrapy.Spider):
    name = 'douban_movie'
    allowed_domains = ['movie.douban.com']
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        for info in response.xpath('//div[@class="info"]'):
            yield {
                'title': info.xpath('div[@class="hd"]/a/span/text()').extract_first(),
                'score': info.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract_first(),
                'director': info.xpath('div[@class="bd"]/p/text()')[0].strip() if len(info.xpath('div[@class="bd"]/p')) == 2 else '',
                'year': info.xpath('div[@class="bd"]/p/text()')[-1].strip().replace('(', '').replace(')', '') if len(info.xpath('div[@class="bd"]/p')) == 2 else info.xpath('div[@class="bd"]/p/text()')[-1].strip()
            }
        next_page = response.xpath('//span[@class="next"]/a/@href')
        if next_page:
            yield scrapy.Request(url=response.urljoin(next_page.extract_first()), callback=self.parse)

代码演示了如何使用Scrapy爬取豆瓣电影TOP250的数据。
首先,我们定义了一个名为DoubanMovieSpider的爬虫类,并设置了访问URL。在parse()函数中,我们首先使用XPath选择器来解析电影数据,然后通过yield关键字返回一个Python字典,字典的键是电影标题、评分、导演和年份。接着,我们使用XPath选择器获取下一页的链接,并使用yield关键字发送一个HTTP请求,进入下一页继续执行parse()函数。

  1. 使用middlewares设置User-Agent
import random
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware

class RandomUserAgentMiddleware(UserAgentMiddleware):
    user_agents = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299',
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
        'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
        'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
        'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
        'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; AS; rv:11.0) like Gecko',
        'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
    ]

    def process_request(self, request, spider):
        user_agent = random.choice(self.user_agents)
        request.headers.setdefault('User-Agent', user_agent)

代码演示了如何使用middlewares设置User-Agent。我们首先创建RandomUserAgentMiddleware类,并继承自Scrapy提供的UserAgentMiddleware类,然后定义user_agents列表,保存多种User-Agent。接着,我们重载process_request()函数,并随机选择一个User-Agent,将其添加到HTTP请求头中。

  1. 将数据写入MySQL数据库
import pymysql
from scrapy.exceptions import DropItem

class MysqlPipeline(object):
    def __init__(self, mysql_host, mysql_db, mysql_user, mysql_pwd, mysql_table):
        self.mysql_host = mysql_host
        self.mysql_db = mysql_db
        self.mysql_user = mysql_user
        self.mysql_pwd = mysql_pwd
        self.mysql_table = mysql_table

    def process_item(self, item, spider):
        if item['title'] and item['score']:
            db = pymysql.connect(host=self.mysql_host, user=self.mysql_user, password=self.mysql_pwd, db=self.mysql_db)
            cursor = db.cursor()
            sql = "INSERT INTO %s (title, score, director, year) VALUES ('%s', '%s', '%s', '%s')" % (self.mysql_table, item['title'], item['score'], item['director'], item['year'])
            try:
                cursor.execute(sql)
                db.commit()
            except Exception as e:
                db.rollback()
                raise DropItem("Failed to insert item: {}".format(e))
            finally:
                db.close()
        return item

代码演示了如何将数据写入MySQL数据库。我们首先定义了一个名为MysqlPipeline的类,并继承自一个Scrapy提供的基本管道类。在__init__()函数中,我们从配置文件或命令行参数中获取MySQL的连接参数,包括主机、数据库名、用户名、密码以及数据表名。在process_item()函数中,我们判断需要保存的数据是否为空,并使用pymysql库连接数据库。然后,我们执行SQL插入语句,并在发生错误时进行回滚操作。最后,在finally中关闭数据库连接。

完结

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/674045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macOS Sonoma 14 beta 2 (23A5276g) ISO、IPSW、PKG 下载

macOS Sonoma 14 beta 2 (23A5276g) ISO、IPSW、PKG 下载 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Linu…

【致敬未来的攻城狮计划】打卡2:keil 程序下载尝试

下载 终于考完试了&#xff0c;然而攻城狮的截止期限也快到了QAQ&#xff0c;得尽快水&#xff08;划掉&#xff09;写几篇文章了&#xff01; 先争取可以成功下载一个空的程序。 先对上一篇文章下载 DFP 也就是 keil MDK Software Packs 做一个补充。我们要下载的是 RA_DFP…

[进阶]TCP通信综合案例:群聊

代码演示如下&#xff1a; 客户端&#xff1a; public class Client {public static void main(String[] args) throws Exception{System.out.println("客户端开启&#xff01;");//1.创建Socket对象&#xff0c;并同时请求与服务端程序的连接。Socket socket new…

网线制作实验

计算机网络综合实训 网线制作 所在院系 计算机与信息工程学院 学科专业名称 计算机科学与技术 导师及职称 柯宗武 教授 提交时间 2023.4.30 计算机网络综合实训报告 一、实验目的 1、掌握三类UTP线缆的制作和测试方法 2、了解三类UTP线缆的作用及布线方式 二、实验内容 1、局…

第二章 进程的描述与控制

目录 一、进程的概念、组成、特征 1.1 进程的概念 1.1.1 程序 1.1.2 进程 1.2 进程的组成 1.3 进程控制块PCB 1.4 进程的特征 二、进程的状态与转换 2.1 进程的状态 2.2 创建态、就绪态 2.3 运行态 2.4 阻塞态 2.5 终止态 2.6 进程状态的转换 2.7 进程的组织 三…

【C++篇】C++字符串:标准库string类

友情链接&#xff1a;C/C系列系统学习目录 知识总结顺序参考C Primer Plus&#xff08;第六版&#xff09;和谭浩强老师的C程序设计&#xff08;第五版&#xff09;等&#xff0c;内容以书中为标准&#xff0c;同时参考其它各类书籍以及优质文章&#xff0c;以至减少知识点上的…

python3.9 安装 pyspider

安装pyspider pip install pyspider 直接报错 Please specify --curl-dir/path/to/built/libcurl 于是从PythonLibs官网 中获取依赖并自行下载到本地 下载与3.9对应的 执行安装 pip install D:\下载\ad3-2.2.1-cp39-cp39-win32.whl 安装成功之后 执行 pip install p…

1748_Perl中使用通配符处理文件

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 使用通配符处理文件一般是用于文件的拷贝、删除以及对文件逐个分析等功能。在Perl中遇到的相应的功能基本上也是如此。通配符匹配处理文件&#xff08;文件名&#xff09;需要使…

前端JavaScript入门-day01

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 JavaScript 介绍 1 JavaScript 是什么 1. JavaScript &#xff08;是什么&#xff1f;&#xff09; 2. 作…

H. Don‘t Blame Me(DP)

Problem - 1829H - Codeforces 很遗憾&#xff0c;这道题目的出题人没有想到一个有趣的故事&#xff0c;所以他只是让你解决以下问题。 给定由n个正整数组成的数组a&#xff0c;计算具有子序列中元素的按位AND在其二进制表示中恰好有k个设置位的非空子序列的数量。答案可能很大…

Winwebmail搭建邮件服务器

配置环境 角色系统IP地址DNS邮件服务器WindowServer2016192.168.1.1/24192.168.1.1客户端1Window10192.168.1.10/24192.168.1.1客户端2Window10192.168.1.20/24192.168.1.1 Winwebmail介绍 WinWebMail是安全高速的全功能邮件服务器&#xff0c;融合强大的功能与轻松的管理为…

macOS Ventura 13.4.1 (22F82|22F2083) 正式版发布,ISO、IPSW、PKG 下载

macOS Ventura 13.4.1 (22F82|22F2083) 正式版发布&#xff0c;ISO、IPSW、PKG 下载 本站下载的 macOS Ventura 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安…

C++ 指针常量与常量指针

指针常量与常量指针的翻译就好比机器学习中Regularization翻译成正则化一样&#xff0c;讲真&#xff0c;正则化这个说法确实要比规则化显得高端些&#xff0c;但是到了理解的时候&#xff0c;还是要按照规则化理解。 指针常量与常量指针这个概念是一样的&#xff0c;英文里没…

【STM32】软件I2C(支持多字节)

I2C简介 I2C总线是一种串行、半双工的总线&#xff0c;主要用于近距离、低速的芯片之间的通信。I2C总线有两根双向的信号线&#xff0c;一根数据线SDA用于收发数据&#xff0c;一根时钟线SCL用于通信双方时钟的同步。 在一个i2c通讯总线中&#xff0c;可连接多个i2c通讯设备&a…

Linux国产操作系统,UCA-系统工程师学习必备技能,系统状态查询和进程管理,uname命令last命令 top命令和 ps命令 kill命令

目录 ​编辑 1.系统状态查询 1. 1.uname命令 1.2. last命令 1.3. top命令 2.进程管理 2.1. ps命令 2.2. kill命令 1.系统状态查询 1. 1.uname命令 rootuos~#: uname rootuos~#: uname -r 4.19是内核&#xff0c;0-6-amd64是架构。 rootuos~#: uname -a eagle操作系统的…

【深入浅出 Spring Security(十一)】授权原理分析和持久化URL权限管理

授权原理分析和持久化URL权限管理 一、必须知道的三大组件&#xff08;Overview&#xff09;二、FilterSecurityInterceptor 源码分析SecurityMetadataSource 分析 三、自定义 FilterSecurityMetadataSource 对象&#xff08;实战&#xff09;自定义表CustomSecurityMetadataSo…

【C++】构造函数调用规则

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01;时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 1、缘起 &#xff08;1&#xff09;默认情况下&#xff0c;C 编译器至少给一个类添加 3 个函数 ① 默认构造函数&#xff08;无参&#…

多无人车自动编队

matlab2016b可运行 Kaveh Fathian - Distributed Formation Control of Cars with Collision Avoidance (google.com)

极致呈现系列之:Echarts桑基图的流动旋律

目录 什么是桑基图桑基图的特点及应用场景Echarts中桑基图的常用属性Vue3中创建桑基图美化桑基图 在各种复杂系统中&#xff0c;我们经常需要了解不同流量之间的关系和流动情况。这种信息的可视化呈现对于我们理解系统的结构和转移过程至关重要。桑基图作为一种强大的可视化工具…

Lambda and Collections

我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起。 为引入Lambda表达式&#xff0c;Java8新增了java.util.funcion包&#xff0c;里面包含常用的函数接口&#xff0c;这是Lambda表达式的基础&#xff0c;Java集合框架也新增部分接口&#xff0c;以便与…