pyquery
当我们谈论爬虫时,我们指的是自动从网页上提取信息的程序。Python是这方面的一门流行语言,因为它有大量的库可以用来帮助实现这一目的。其中,pyquery就是一个强大的库,它允许你像使用jQuery那样查询HTML文档。
- 什么是pyquery?
pyquery允许你对HTML文档进行选择、提取和操作,就像jQuery一样。如果你熟悉jQuery,使用pyquery会很自然。但即使你不熟悉,它也很直观。 - 如何安装?
使用pip进行安装:
pip install pyquery
- pip install pyquery
1 从字符串初始化
from pyquery import PyQuery as pq
html = '<div><span>Hello, World!</span></div>'
doc = pq(html)
print(doc('span').text())
>>> Hello, World!
2 从URL初始化
doc = pq(url='http://example.com')
print(doc('title').text())
3 从文件初始化
doc = pq(filename='path_to_file.html')
- 基础选择器
- doc(‘#id’): 选择ID
- doc(‘.class’): 选择class
- doc(‘tag’): 选择标签
- DOM操作
- addClass、removeClass
- attr、removeAttr
- text、html
等等…
- 使用pyquery进行爬虫
首先,常与requests库结合使用,先获取HTML内容,再用pyquery解析。
例如,获取简书首页文章的标题:
import requests
from pyquery import PyQuery as pq
url = 'https://www.jianshu.com'
response = requests.get(url)
doc = pq(response.text)
titles = doc('.title').items()
for title in titles:
print(title.text())
- 注意事项
- 要确保爬取的内容不违反目标网站的robots.txt。
- 要尊重网站的访问频率,不要频繁请求以免给目标服务器造成负担。
- 随时可能面临网站结构的改变,导致爬虫失效。所以要有错误处理和可能的备选方案。
总结:pyquery是一个非常强大和灵活的库,它可以使HTML文档查询和操作变得非常简单。
获取utf-8
获取UTF-8编码的文档涉及几个步骤,取决于你是从何处获取文档的。这里,我会为你列出从网页和本地文件获取UTF-8编码的文档的方法。
- 从网页获取UTF-8编码的文档
使用Python的requests库可以轻松获取网页内容。默认情况下,requests会从HTTP头中尝试推断内容的编码,但我们可以手动设置它为UTF-8。
import requests
url = 'https://example.com'
response = requests.get(url)
response.encoding = 'utf-8' # 确保响应是UTF-8编码的
text = response.text
- 从本地文件读取UTF-8编码的文档
当你从本地文件读取内容时,你可以在open函数中指定编码为UTF-8。
pythonCopy code
with open('path_to_file.txt', 'r', encoding='utf-8') as file:
content = file.read()
注意事项:
- 确保目标文档确实是UTF-8编码的。如果它不是UTF-8编码,但你试图以UTF-8的方式解码,可能会遇到UnicodeDecodeError错误。
- 当你不确定文档的编码时,可以使用诸如chardet这样的库来检测文档的编码。
使用chardet来检测编码:
pythonCopy code
import chardet
raw_data = open('path_to_file.txt', 'rb').read()
result = chardet.detect(raw_data)
char_encoding = result['encoding']
然后,你可以使用检测到的编码来读取文件或解码网页内容。
爬取到数据库
from pyquery import PyQuery as pq
import sqlite3
DATABASE = "./database/sqliteFlask.db"
def connect_db():
return sqlite3.connect(DATABASE)
def newsUrl():
url = 'https://stock.cngold.org/rumen/'
# 通过链接和编码获取页面内容
doc = pq(url=url)
# doc.encoding = 'utf-8'
# print(doc)
# 通过css选择器获取所有的链接标签
lista = doc('.news_list li a')
# print("lista", lista)
for i, item in enumerate(lista):
# 通过yield关键词将newsUrl变成生成器,可进行循环迭代
yield doc(item).attr('href')
# newsUrl()
def parsePage(url):
doc = pq(url=url)
# 获取标题
titleDom = doc('h1')
title = titleDom.text()
print("title", title)
# 获取简介
summary = doc(
'body > div.main.w1000 > div.article.clearfix > div.main_left.fl > div.summary > p').text()
tempDom = doc(
'body > div.main.w1000 > div.article.clearfix > div.main_left.fl > div.article_con')
tempDom.remove('script')
# 删除内容中的script标签
# 通过获取下一页标签,获取下一页新闻内容
content = tempDom.html()
nextPageUrl = doc('.listPage a:contains("下一页")').attr('href')
while nextPageUrl:
tempDoc = pq(nextPageUrl, encoding="utf-8")
tempDom = tempDoc(
'body > div.main.w1000 > div.article.clearfix > div.main_left.fl > div.article_con')
tempDom.remove('script')
content += tempDom.html()
nextPageUrl = tempDoc('.listPage a:contains("下一页")').attr('href')
# 设置数据库插入语句
sqlStr = "insert into stocknews (title,summary,content) values ('{}','{}','{}')".format(
title, summary, content)
# 插入到数据库
db.execute(sqlStr)
db.commit()
print(title)
# parsePage('https://stock.cngold.org/rumen/c6694940.html')
if __name__ == "__main__":
# 连接数据库
db = sqlite3.connect(DATABASE)
# 获取游标
# cursor = db.cursor()
newsListUrl = newsUrl()
for url in newsListUrl:
print(url)
parsePage(url)
db.close()
使用pyquery来爬取页面中的图片并确保文件名不重复的方法如下:
- 使用pyquery来解析页面并提取所有图片的src属性。
- 使用requests下载图片。
- 为了避免文件名重复,可以使用图片的URL的哈希值或加入时间戳来生成唯一的文件名。
以下是一个具体的实现示例:
import os
import requests
from pyquery import PyQuery as pq
import hashlib
import time
def get_all_image_urls(url):
# 获取网页内容
response = requests.get(url)
doc = pq(response.text)
# 提取所有图片的URL
img_urls = [img.attr("src") for img in doc("img").items()]
return img_urls
def unique_filename(base_name):
"""生成一个基于时间戳和哈希的唯一文件名"""
file_name, file_extension = os.path.splitext(base_name)
timestamp = str(int(time.time()))
hashed = hashlib.md5((file_name + timestamp).encode()).hexdigest()[:10]
return f"{file_name}_{hashed}{file_extension}"
def download_images_from_url_list(url_list, dest_folder='.'):
if not os.path.exists(dest_folder):
os.makedirs(dest_folder)
for url in url_list:
response = requests.get(url)
# 使用原始文件名,但添加哈希值避免重复
filename = os.path.join(dest_folder, unique_filename(os.path.basename(url)))
with open(filename, 'wb') as file:
file.write(response.content)
print(f"Downloaded {url} to {filename}")
if __name__ == "__main__":
page_url = 'https://example.com' # 你想爬取的页面URL
image_urls = get_all_image_urls(page_url)
download_images_from_url_list(image_urls, 'downloaded_images')
Pyppeteer
Pyppeteer 是一个 Python 库,它是 Puppeteer(一个 Node 库)的端口,可提供通过 DevTools 协议控制无头 Chrome 或 Chromium 的能力。无头浏览器是没有图形用户界面的浏览器,适用于自动化测试、网络抓取等场景。
安装 Pyppeteer
pip install pyppeteer
基本使用
使用 Pyppeteer 最基本的流程是启动浏览器、打开页面、执行一些操作(如点击、输入文本等),然后关闭浏览器。下面是一个简单的例子,展示了这个过程:
import asyncio
from pyppeteer import launch
async def main():
# 启动浏览器
browser = await launch()
# 打开一个新页面
page = await browser.newPage()
# 访问页面await page.goto('https://example.com')
# 截图await page.screenshot({'path': 'example.png'})
# 获取页面内容
content = await page.content()
# 打印页面内容print(content)
# 关闭浏览器await browser.close()
# 运行 asyncio 程序
asyncio.get_event_loop().run_until_complete(main())
页面交互
Pyppeteer 支持各种页面交互,例如点击按钮、输入文本、滚动页面等:
# 点击一个按钮
await page.click('selector')
# 输入文本
await page.type('input[name=myinput]', 'hello')
# 滚动页面到底部
await page.evaluate('window.scrollTo(0, document.body.scrollHeight)')
等待元素
在网页操作中,经常需要等待某个元素加载完成。Pyppeteer 提供了多种等待元素的方法:
# 等待元素出现在页面中
await page.waitForSelector('selector')
# 等待函数执行结果为真
await page.waitForFunction('window.innerWidth < 100')
页面导航
Pyppeteer 也支持页面导航,如前进、后退:
# 后退
await page.goBack()
# 前进
await page.goForward()
评估脚本和函数
你可以在页面上下文中执行 JavaScript 代码:
# 在页面中执行脚本
result = await page.evaluate('() => document.title')
print(result)
配置 Pyppeteer
Pyppeteer 允许你配置无头浏览器,例如设置无头模式、窗口大小、用户代理等:
# 启动浏览器的配置选项
browser = await launch(headless=False, args=['--window-size=1920,1080'])
# 设置用户代理
await page.setUserAgent('My User Agent')
使用代理
在某些情况下,你可能需要通过代理服务器来访问网页,你可以在启动浏览器时设置代理:
browser = await launch(args=['--proxy-server=http://myproxy:port'])
异常处理
在使用 Pyppeteer 时,可能会遇到各种异常,你应该处理这些异常以避免程序崩溃:
pythonCopy code
try:
await page.goto('https://example.com')
except Exception as e:
print(f'An error occurred: {e}')
Numpy初识
NumPy(Numerical Python的缩写)是一个开源的Python科学计算基础库。它包含了一个强大的N维数组对象ndarray,提供了矩阵运算的功能,也包含了许多高级的数值编程工具,如:矩阵数据类型、高效的元素级数组运算以及用于整合C/C++和Fortran代码的工具等。
安装NumPy通常很简单,可以直接使用pip:
pip install numpy
NumPy 基本属性
- ndarray.ndim
- 数组的维数,或者说“轴”的数量。例如,二维数组具有2个轴。
- ndarray.shape
- 数组的形状,返回一个元组,每个数字表示该维的大小(元素个数)。
- ndarray.size
- 数组中所有元素的数量。
- ndarray.dtype
- 数组元素类型的对象,可以是标准的Python类型,也可以是NumPy提供的数据类型。
- ndarray.itemsize
- 数组中每个元素的字节大小。
- ndarray.data
- 包含数组实际元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用元素。
NumPy 创建方法
NumPy提供了多种创建数组的方法:
- 从Python列表创建
import numpy as np
a = np.array([1, 2, 3])
- 使用初始化函数
- zeros:创建指定大小的数组,数组元素以0来填充。
np.zeros((3,4))
- ones:创建指定形状的数组,数组元素以1来填充。
np.ones((2,3,4), dtype=np.int16)
- empty:创建数组,其初始内容是随机的,取决于内存的状态。
np.empty((2,3))
- arange:返回一个有终点和起点的固定步长的排列。
np.arange(10, 50, 5)
- linspace:在指定的间隔内返回均匀间隔的数字。
np.linspace(0, 2, 9)
- random:生成随机数或随机数组。
np.random.rand(2,3)
- 从已有的数据创建
- 可以使用np.array()将Python序列转换为ndarray,或者使用np.asarray()和np.asanyarray()进行转换。
- 特殊库函数
- 如:np.eye()创建一个二维数组,对角线上为1,其余为0。
import numpy as np
# 创建一个长度为5的空数组,默认数据类型为float64
a = np.empty(5)
print(a)
# 创建一个3x3的单位矩阵
b = np.eye(3)
print(b)
# 创建一个元素值都是1的3x4数组
c = np.ones((3,4))
print(c)
# 创建一个由10到50的数构成的数组,步长为5
d = np.arange(10, 50, 5)
print(d)
# 创建一个线性空间数组,从0到2,共有9个数
e = np.linspace(0, 2, 9)
print(e)
# 创建一个2x3的随机数组
f = np.random.random((2,3))
print(f)
每次调用np.random.random可能会得到不同的结果,因为它按照某个随机数生成器的算法,从概率分布中采样出一组数。
NumPy 运算操作
NumPy 提供了一系列的运算操作,可以让我们对数组进行数学计算和逻辑运算,包括但不限于以下几类:
数学运算
- 基本运算:
NumPy 允许你进行数组与数组的运算,或者数组与单个数字的运算。它会应用元素级别的加、减、乘、除等操作。
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
c = a + b # 数组相加
d = a - b # 数组相减
e = a * b # 元素相乘
f = a / b # 元素相除
- 广播(Broadcasting):
当操作两个形状不同的数组时,NumPy会应用广播规则。
a = np.array([1, 2, 3])
b = 2
c = a * b # [2, 4, 6]
- 更复杂的数学运算:
NumPy 提供了大量的数学函数,可以对数组中的元素进行复杂的数学运算,如三角函数、指数函数、对数函数等。
a = np.array([1, 2, 3, 4])
np.sin(a) # 计算数组中每个元素的正弦
np.exp(a) # 计算数组中每个元素的指数
np.sqrt(a) # 计算数组中每个元素的平方根
- 聚合函数:
NumPy 也提供了如求和、求积、最大值、最小值、平均值等聚合函数。
a = np.array([[1, 2], [3, 4]])
np.sum(a) # 数组中所有元素的总和
np.prod(a) # 数组中所有元素的乘积
np.mean(a) # 数组元素的平均值
np.min(a) # 最小值
np.max(a) # 最大值
np.var(a) # 方差
np.std(a) # 标准差
np.sum(a, axis=0) # 对指定轴的元素进行求和
逻辑运算
- 基本比较:
可以对数组中的元素进行比较操作,得到布尔数组作为结果。
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
a == b # 对应元素比较
a > b # 对应元素比较
- 布尔运算:
可以应用逻辑运算符来进行布尔逻辑运算。
在这里插入代码片
a = np.array([True, True, False, False])
b = np.array([True, False, True, False])
np.logical_and(a, b) # 逻辑与
np.logical_or(a, b) # 逻辑或
np.logical_not(a) # 逻辑非
线性代数运算
NumPy 提供了一系列线性代数的函数,例如:
- 点积:
#苹果 2元, 香蕉 3元
#购买 3个苹果 5个香蕉
#数量的数组:【2,3】
#价格的向量:【3,5】
#总共花费:3 * 2 + 5 * 3 = 21元
#[2,3] · [3,5] = 3 * 2 + 5 * 3
a = np.array([1, 2])
b = np.array([3, 4])
np.dot(a, b) # 点积
- 矩阵乘法:
# 苹果 香蕉 橘子
#价格 2 3 4
#老陈量 2 1 3
#小明 3 5 2
#小红 1 0 1
#价格向量 【2,3,4】
#数量矩阵【 【2,1,3】,【3,5,2】,【1,0,1】】
每一个人的数量*价格向量 = 每个人花费的总价去
#【19,29,6】
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
np.matmul(a, b) # 矩阵乘法
数组索引与切片
NumPy还提供了丰富的索引和切片功能,可以让我们访问和修改数组的特定部分。
- 切片:
a = np.array([1, 2, 3, 4, 5])
a[1:4] # 获取索引1到3的元素
- 高级索引:
a = np.array([[1, 2], [3, 4], [5, 6]])
a[[0, 1, 2], [0, 1, 0]] # 获取位置(0,0),(1,1),(2,0)的元素
- 布尔索引:
a = np.array([1, 2, 3, 4, 5])
b = a > 2
a[b] # 获取所有大于2的元素
以上只是NumPy功能的冰山一角。NumPy非常强大,是数据分析和科学计算领域中不可或缺的工具。在实际的数据处理和分析工作中,你会发现它的强大功能。
点积和矩阵乘法
点积和矩阵乘法对于刚接触线性代数的人来说可能有些混淆,但其实它们的概念是可以通过简单的例子来解释的。
点积(Dot Product)
想象一下你在超市买了一些苹果和香蕉。苹果的价格是每个2元,香蕉是每个3元。如果你买了3个苹果和5个香蕉,总花费是多少呢?你可以这样计算:
- 苹果的花费:3个苹果 * 2元/个 = 6元
- 香蕉的花费:5个香蕉 * 3元/个 = 15元
- 总花费:6元 + 15元 = 21元
这个操作就是一个点积的例子。你有两个向量,数量向量 [3, 5] 和价格向量 [2, 3],点积就是对应元素相乘然后求和:
(3∗2)+(5∗3)=6+15=21(3∗2)+(5∗3)=6+15=21
在 NumPy 中,你可以这样计算点积:
import numpy as np
quantities = np.array([3, 5])
prices = np.array([2, 3])
total_cost = np.dot(quantities, prices)
print(total_cost) # 输出: 21
矩阵乘法(Matrix Multiplication)
现在,让我们扩展这个例子到矩阵乘法。假设你不仅买了苹果和香蕉,还买了橘子,价格分别是2元、3元和4元。你和你的两个朋友都买了不同数量的这些水果:
- 你买了3个苹果、5个香蕉、2个橘子
- 你的第一个朋友买了2个苹果、1个香蕉、3个橘子
- 你的第二个朋友买了1个苹果、0个香蕉、1个橘子
现在你有了一个数量矩阵和一个价格向量。矩阵乘法就是这样的:你将数量矩阵的每一行(代表每个人买的水果)和价格向量做点积。
在 NumPy 中,你可以使用 np.dot() 或者 @ 运算符来完成矩阵乘法:
import numpy as np
quantities = np.array([
[3, 5, 2], # 你的数量
[2, 1, 3], # 你第一个朋友的数量
[1, 0, 1] # 你第二个朋友的数量
])
prices = np.array([2, 3, 4]) # 水果的价格
total_costs = quantities.dot(prices)
# 或者# total_costs = quantities @ pricesprint(total_costs) # 输出: [23 16 6]
这里的结果 [23, 16, 6] 表示你的总花费是23元,你的第一个朋友的总花费是16元,你的第二个朋友的总花费是6元。
所以,点积是一对一对元素相乘然后加起来,而矩阵乘法是矩阵的每一行与另一个矩阵的每一列做点积,最后得到一个新的矩阵。这是线性代数中非常重要的运算,也是许多数学、物理和工程问题的基础。