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

文章目录

  • 认识网络爬虫
  • 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中关闭数据库连接。

完结

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s使用ceph存储

文章目录 初始化操作k8s使用ceph rbdvolumePV静态pv动态pv k8s使用cephfsvolume静态pv 初始化操作 ceph创建rbd存储池 ceph osd pool create k8s-data 32 32 replicated ceph osd pool application enable k8s-data rbd rbd pool init -p k8s-dataceph添加授权&#xff0c;需…

吴恩达ChatGPT《Building Systems with the ChatGPT API》笔记

1. 课程介绍 使用ChatGPT搭建端到端的LLM系统 本课程将演示使用ChatGPT API搭建一个端到端的客户服务辅助系统&#xff0c;其将多个调用链接到语言模型&#xff0c;根据前一个调用的输出来决定使用不同的指令&#xff0c;有时也可以从外部来源查找信息。 课程链接&#xff1a…

client-go的Indexer三部曲之三:源码阅读

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 《client-go的Indexer三部曲》全部链接 基本功能性能测试源码阅读 本篇概览 本文是《client-go的Indexer三部曲》系列的终篇&#xff0c;主要任务是阅读和…

VR全景智慧园区,沉浸式数字化体验,720度全视角展示

导语&#xff1a; 随着科技的迅猛发展&#xff0c;虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;全景技术已经成为了人们趋之若鹜的新兴领域。 而城市园区作为现代社会的重要组成部分&#xff0c;也正在积极寻求创新的方式来吸引更多的人流和投资。 一&…

C++基础

C基础入门 1 C初识 1.1 第一个C程序 编写一个C程序总共分为4个步骤 创建项目创建文件编写代码运行程序 1.1.1 创建项目 ​ Visual Studio是我们用来编写C程序的主要工具&#xff0c;我们先将它打开 1.1.2 创建文件 右键源文件&#xff0c;选择添加->新建项 1.1.3 编…

SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

SignalR快速入门 ~ 仿QQ即时聊天&#xff0c;消息推送&#xff0c;单聊&#xff0c;群聊&#xff0c;多群公聊&#xff08;基础》提升&#xff0c;5个Demo贯彻全篇&#xff0c;感兴趣的玩才是真的学&#xff09; 官方demo:http://www.asp.net/signalr/overview/getting-started…

【面试】标准库相关题型(二)

文章目录 1. deque底层实现原理1.1 概述1.2 原理图1.3 类结构1.4 操作函数 2. 什么时候使用vector、list、deque2.1 vector2.2 list2.3 deque 3. priority_queue的底层实现原理3.1 一句话概括&#xff1a;用堆来实现优先级队列3.2 堆结构3.3 底层容器3.4 STL对堆结构提供的接口…

Java-API简析_java.lang.SecurityManager类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131346082 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…

Python入门(二十七)测试(二)

测试&#xff08;二&#xff09; 1.测试类2.各种断言方法3.一个要测试的类4.测试AnonymousSurvey类5.方法setUp() 1.测试类 前面我们编写了针对单个函数的测试&#xff0c;下面来编写针对类的测试。很多程序中都会用到类&#xff0c;因此证明我们的类能够正确工作大有裨益。如…

学了那么长时间的编程,C语言的各种操作符都搞不懂?点开这里有详细的介绍—>

目录 前言 一、原码、反码、补码的基础概念 1.原码 2.反码 3.补码 二、原码、反码、补码的计算方法 1.原码 2.反码 3.补码 三、算术操作符 四、移位操作符 1. 左移操作符 移位规则&#xff1a; 2. 右移操作符 移位规则&#xff1a; &#xff08;1&#xff09; …

电脑怎么录屏?推荐2款录制电脑屏幕的软件!

案例&#xff1a;我经常需要把电脑上的内容分享给别人&#xff0c;一般通过手机拍摄的方式。这就导致视频十分模糊&#xff0c;给人的观感不太好&#xff0c;有没有什么方法可以实现在电脑上直接录屏&#xff1f; 【我想录制我的电脑屏幕上的内容分享给别人&#xff0c;但是我…

几个SQL的高级写法

一、ORDER BY FLELD() 自定义排序逻辑 MySql 中的排序 ORDER BY 除了可以用 ASC 和 DESC&#xff0c;还可以通过 ORDER BY FIELD(str,str1,...) 自定义字符串/数字来实现排序。这里用 order_diy 表举例&#xff0c;结构以及表数据展示&#xff1a; ORDER BY FIELD(str,str1,..…

【Neo4j教程之CQL函数基本使用】

&#x1f680; Neo4j &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;C…

3d重建+神经渲染

3d重建 基于深度相机(结构光、TOF、双目摄像头)的三维重建基于图像的三维重建&#xff1a;深度学习基于视觉几何的传统三维重建&#xff1a;这种三维重建方法研究时间比较久远&#xff0c;技术相对成熟。主要通过多视角图像对采集数据的相机位置进行估计&#xff0c;再通过图像…

一种对不同类型齐格勒-尼科尔斯 P-I-D 控制器调谐算法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

常用工具类之AJ-Captcha入门

1.引入MAVEN依赖 若依官方引入的是1.2.7版本。我选择了目前最常用的1.3.0版本。 在项目中给的 ruoyi-framework\pom.xml 添加依赖 <!-- anji滑块验证码 --><dependency><groupId>com.anji-plus</groupId><artifactId>spring-boot-starter-captc…

通过调整图像hue值并结合ImageEnhance库以实现色调增强

前言 PIL库中的ImageEnhance类可用于图像增强&#xff0c;可以调节图像的亮度、对比度、色度和锐度。 通过RGB到HSV的变换加调整可以对图像的色调进行调整。 两种方法结合可以达到更大程度的图像色调增强。 调整hue值 __author__ TracelessLe __website__ https://blog…

vue2中引入天地图及相关配置

前言 项目中需要引入特殊用途的地图&#xff0c;发现天地图比高德地图、百度地图要更符合需求&#xff0c;于是看了看天地图。 正文 vue2项目中如何引入天地图并对相关的配置进行修改使用呢&#xff1f;官方给的4.0版本的使用说明。 引入&#xff1a; 进入到public/index.html中…

Cocos Creator3D:制作可任意拉伸的 UI 图像

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 制作可任意拉伸的 UI 图像 UI 系统核心的设计原则是能够自动适应各种不同的设备屏幕尺寸&#xff0c;因此我们在制作 UI 时需要正确设置每个控件元素的尺寸&#xff08;size&#…

TypeScript ~ TS 掌握自动编译命令 ③

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; TypeScript ~ TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &…