注:本文章为学习过程中对知识点的记录,供自己复习使用,也给大家做个参考,如有错误,麻烦指出,大家共同探讨,互相进步。
借鉴出处:
该文章的路线和主要内容:崔庆才(第2版)python3网络爬虫开发实战
def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
io.DEFAULT_BUFFER_size
。在许多系统上,缓冲区通常为4096或8192字节长。“交互式”文本文件(isatty()返回True的文件)使用行缓冲。其他文本文件使用上述策略用于二进制文件。但常用的三个参数就是file、mode、encoding了。
mode的几种模式:
每回调用open方法后,要用close()方法关闭文件对象。
为了简化方法,采用with as语法。当with控制块语句结束时,文件会自动关闭,意味着不需要在调用close方法。
with open('movies.txt', 'w', encoding='utf-8') as file:
file.write(f'名称':{name}\n}
file.write(f'类别':{categories}\n}
file.write(f'上映事件':{published_at}\n}
file.write(f'评分':{score}\n}
在JSON对象中用’[]'包围的内容相当于数组,数组中的每个元素都可以是任意类型,数据结构类型为[“java”,“javascript”,“vb”,…]。‘{}’包围的内容相当于对象,数据结构类型是{key1:value1,key2:value2,…}
JSON可以有对象和数组两种形式自由组合,能够嵌套无限次,并且结构清晰,是数据交换的极佳实现方式。
JSON库中的loads方法将JSON文本字符串转为JSON对象,反过来通过dumps方法将JSON对象转换为文本字符串。
loads
输入:
import json
str = '''[{"name":"Bob"},{"name":"Tom"}]'''
print(type(str))
data = json.loads(str)
print(type(data))
print(data)
print(data[1].get('name'))
输出:
<class 'str'>
<class 'list'>
[{'name': 'Bob'}, {'name': 'Tom'}]
Tom
注意:JSON字符串的表示需要用双引号,否则loads方法会解析失败。同时还有load方法,与loads功能一致,只不过load接收的是文件操作对象,loads接收的是JSON字符串。
dumps
输入:
import json
data = [{'name':'张三'},{'name':'Tom'}]
with open('data.json','w',encoding='utf-8') as file:
# indent缩进字符的个数;ensure_ascii=False表示不让中文转Unicode字符
file.write(json.dumps(data,indent=2,ensure_ascii=False))
输出:
# data.json
[
{
"name": "张三"
},
{
"name": "Tom"
}
]
注意:dumps同样有dump方法,与load使用方式一致。
CSV比Excel文件更加简洁,XLS文本是电子表格,包含文本、数值、公式和格式等内容,CSV中不包含这些,就是以特定字符作为分隔符的纯文本,结构简单清晰。所以,有时候使用CSV来存储数据是比较方便的。
写入
输入:
import csv
with open('data.csv','w',encoding='utf-8') as csvFile:
# writer初始化csv写入对象;delimiter用于传列与列之间的分隔符
writer = csv.writer(csvFile, delimiter=',')
writer.writerow(['id','name'])
# writerow写入单行数据
writer.writerow(['10001','Tom'])
writer.writerow(['10002','Jack'])
# writerows写入多行数据
writer.writerows([['10003','Jerry'],['10004','Bob']])
输出:
# data.csv
id,name
10001,Tom
10002,Jack
10003,Jerry
10004,Bob
但一般情况下,爬虫爬取的都是结构化的数据,我们一般会用字典表示这种数据。csv库提供了字典的写入方式,如下:
输入:
import csv
with open('data.csv','w',encoding='utf-8') as csvFile:
fieldnames = ['id', 'name']
# DictWriter初始化csv写入对象并定义好字段;delimiter用于传列与列之间的分隔符
writer = csv.DictWriter(csvFile, fieldnames=fieldnames, delimiter=';')
# writeheader方法写入fieldnames头信息
writer.writeheader()
# writerow写入单行数据
writer.writerow({'id':'10001','name':'Tom'})
writer.writerow({'id':'10002','name':'Jack'})
# writerows写入多行数据
writer.writerows([{'id':'10003','name':'Jerry'},{'id':'10004','name':'Bob'}])
输出:
# data.csv
id;name
10001;Tom
10002;Jack
10003;Jerry
10004;Bob
同时,通过pandas库DataFrame对象的to_csv方法将数据写入CSV文件中。
安装pandas库pip install pandas
输入:
import pandas as pd
data = [
{'id':'10001','name':'Tom'},
{'id':'10002','name':'Jack'}
]
df = pd.DataFrame(data)
df.to_csv('data.csv', index=False)
输出:
# data.csv
id,name
10001,Tom
10002,Jack
读取
采用csv中的reader函数进行读取csv文件。
输入:
import csv
with open('data.csv','r',encoding='utf-8') as csvFile:
reader = csv.reader(csvFile)
for row in reader:
print(row)
输出:
['id', 'name']
['10001', 'Tom']
['10002', 'Jack']
也可以用read_csv方法将数据从CSV文件中读取出来。
输入:
import pandas as pd
df = pd.read_csv('data.csv')
print(df)
# 转换成列表或元组
data = df.values.tolist()
print(data)
输出:
id name
0 10001 Tom
1 10002 Jack
[[10001, 'Tom'], [10002, 'Jack']]
关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以关系型数据库中数据的存储方式就是行列组成的表,每一列代表一个字段、每一行代表一条记录。表可以看作某个实体的集合,实体之间存在的联系需要通过表与表之间的关联关系体现,例如主键和外键的关联关系。由多个表组成的数据库,就是关系型数据库。
关系型数据库有多种,例如SQLite、MySQL、Oracle、SQL Server、DB2等。
安装连接库pip install pymysql
输入:
import pymysql
# 与mysql建立连接,填写mysql的host,port,user,password
db = pymysql.connect(host='127.0.0.1',port=3306, user='root', password='password')
# 获取mysql的操作游标,利用游标执行sql语句
cursor= db.cursor()
sql1 = 'CREATE DATABASE IF NOT EXISTS TestDataBase;'
sql2 = 'USE TestDataBase;'
sql3 = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL ,name VARCHAR(255) NOT NULL , primary key (id));'
# execute执行语句
cursor.execute(sql1)
cursor.execute(sql2)
cursor.execute(sql3)
data = [{'id':'100001','name':'Tom'},{'id':'100002','name':'Jerry'},{'id':'100003','name':'Jack'}]
# 插入数据
sql4 = 'INSERT INTO students(id, name) values(%s ,%s)'
try:
for i in range(len(data)):
cursor.execute(sql4,(data[i].get("id"),data[i].get("name")))
# 提交到数据库
db.commit()
except EOFError as e:
print(e)
# 如果执行异常,用rollback回滚
db.rollback()
# 更新数据
sql5 = 'UPDATE students SET name=%s WHERE id=%s;'
try:
cursor.execute(sql5,('Bob','100001'))
db.commit()
except EOFError as e:
print(e)
db.rollback()
# 删除数据
sql6 = 'DELETE FROM students where name=%s;'
try:
cursor.execute(sql6,('Jerry'))
db.commit()
except EOFError as e:
print(e)
db.rollback()
# 查询数据
sql7 = 'SELECT * FROM students;'
try:
cursor.execute(sql7)
# 如果先fetchone再fetchall,那fetchall就查询不到第一条数据了
# one = cursor.fetchone()
alls = cursor.fetchall()
for row in alls:
print(row)
except EOFError as e:
print(e)
db.rollback()
db.close()
其他知识点:
事务的4个属性:
属性 | 解释 |
---|---|
原子性 | 事务是一个不可分割的工作单位,一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作 |
一致性 | 事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态。 |
隔离性 | 一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰 |
持久性 | 持续性也称持久性,指一个事务一旦提交,它对数据库中数据做的改变就应该是永久性的。接下来的其他操作或故障不应该对数据有任何影响。即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态。 |
pip install pymongo
import pymongo
'''建立连接'''
client = pymongo.MongoClient(host='localhost',port=27017)
# 或者这种方式client = pymongo.MongoClient('mongodb://localhost:27017')
'''指定数据库'''
db = client.test
# 或者这种方式db = client['test']
'''指定集合'''
collection = db.students
# 或者这种方式collection = db['students']
'''插入数据'''
student1 = {'id':'100001','name':'Tom'}
result = collection.insert(student1)
# 每条数据都有一个_id属性作为唯一标识。如果没有显式指明该属性,那么MongoDB会自动产生一个Object类型的_id属性,insert方法会在执行后返回_id值。
print(result)
'''插入多条数据'''
student2 = {'id':'100002','name':'Jerry'}
result = collection.insert([student1,student2])
# PyMongo3.x版本中推荐使用insert_one和insert_many方法,继续使用insert也没问题。
print(result)
'''查询'''
result = collection.find_one({'name':'Tom'})
# find_one查询一条数据;find查询所有数据。返回的是一个字典类型。
print(result)
'''计数'''
count = collection.find().count()
print(count)
'''排序'''
#ASCENDING升序,DESCENDING降序
results = collection.find().sort('name', pymongo.ASCENDING)
print([result['name'] for result in results])
'''偏移'''
# skip(2)偏移2个位置即忽略前两个元素,获取第三个及以后的元素
results = collection.find().sort('name', pymongo.ASCENDING).skip(2)
print([result['name'] for result in results])
# limit(2)指定获取前两个
# 数据库中数据量偏大时,最好不要使用大偏移来查询数据,可能导致内存溢出。
results = collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2)
print([result['name'] for result in results])
# 数据量偏大时,根据id查询,这里需要记录好上次查询的_id
from bson.objectid import ObjectId
collection.find({'_id':{'$gt':ObjectId('2738192731720a1902c38103d')}})
'''更新'''
student = collection.find_one({'id':'100001'})
student['name'] = 'Bob'
result = collection.update({'id':'100001'},student)
print(result)
'''删除'''
result = collection.remove({'name':'Tom'})
print(result)
'''还有find_one_and_delete\find_one_and_replace\find_one_and_update\create_index\create_indexes\drop_index等方法,实际使用时,再根据官方提供的api操作即可'''
还有一些常用操作符,如比较符号、正则匹配 $ regex、类型判断$type、文本查询 $ text等,用到时百度即可。
Redis是一个基于内存的、高效的键值型数据库,存取效率极高,而且支持多种数据存储结构,使用起来也非常简单。
安装pip install redis
输入:
from redis import StrictRedis
redis = StrictRedis(host='localhost',port=6379, db=0, password='password')
## 构建连接的其他方法
# 1、ConnectionPool连接方式
# from redis import StrictRedis,ConnectionPool
# pool = ConnectionPool(host='localhost',port=6379, db=0, password='password')
# redis = StrictRedis(connection_pool=pool)
# 2、通过URL连接
# url = 'redis://:redisredis@localhost:6379/0'
# pool = ConnectionPool.from_url(url)
# redis = StrictRedis(connection_pool=pool)
redis.set('name','Bob')
print(redis.get('name'))
输出:
b’Bob’
1、键的一些判断和操作方法
2、键值对存储的相关方法
3、列表操作
4、集合操作
5、有序集合操作
6、散列操作
Elasticsearch是一个开源的搜索引擎,建议在一个全文搜索引擎库Lucene的基础之上。(Lucene拥有最先进、高性能和全功能搜索引擎功能的库,但也仅仅只是一个库。)Elasticsearch也是使用Java编写的,其内部使用Lucene实现索引和搜索,但它的目标是使全文检索变得简单,相当于Lucene的一层封装,它提供了一套简单一致的RESTful Api来帮助我们实现存储和检索。
特点:
介绍几个概念:
安装pip install elasticsearch
输入:
from elasticsearch import Elasticsearch
'''建立连接'''
es = Elasticsearch(['http://[username:password@]hostname:port'], verify_certs=True)
'''创建索引'''
# 合理利用ignore可以避免没必要的错误
result = es.indices.create(index='news', ignore=400)
print(result)
'''删除索引'''
result = es.indices.delete(index='news', ignore=[400,404])
print(result)
'''插入数据'''
data = {'title':'乘风破浪会有时,直挂云帆济沧海','url':'http://view.inew.com/asd098092sa8d90890890'}
#create需要指定id; es.index(index='news', body=data) --- index不需要指定id,会自动生成。
result = es.create(index='news', id=1, body=data)
print(result)
'''更新数据'''
data = {'title':'乘风破浪会有时,直挂云帆济沧海','url':'http://view.inew.com/asd098092sa8d90890890','date':'2022-10-23'}
#es.index(index='news',doc_type='politics',body=data, id=1)
result = es.update(index='news', body=data, id=1)
print(result)
'''删除数据'''
result = es.delete(index='news', id=1)
print(result)
'''查询数据'''
# 根据索引查询该索引下的所有数据
result = es.search(index='news')
dsl = {
'query':{
'match':{
'title':'hello'
}
}
}
# 全文检索符合的字段
result = es.search(index='news', body=dsl)
在爬取过程中,可能需要一些进程间的通信机制:
为了降低这些进程的耦合度,需要一个类似消息队列的中间件来存储和转发消息,实现进程间的通信。有了消息队列中间件之后,以上各机制中的两个进程就可以独立执行,它们之间的通信则由消息队列实现。
RabbitMQ介绍
RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议实现,其主要特点有面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全性。具有以下特点:
pip install pika
基本了解:
从本质上讲是一个生产者-消费者模型。
'''声明一个队列'''
import pika
QUEUE_NAME = 'scrape'
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue=QUEUE_NAME)