手机版网站嵌入代码,阳江网络问政平台电话,杭州建设网站公司哪家好,一级a行做爰片免费网站在爬虫项目中#xff0c;我们需要将目标站点数据进行持久化保存#xff0c;一般数据保存的方式有两种#xff1a;
文件保存数据库保存
在数据保存的过程中需要对数据完成去重操作#xff0c;所有需要使用 redis 中的 set 数据类型完成去重。
1.CSV文件存储
1.1 什么是c…在爬虫项目中我们需要将目标站点数据进行持久化保存一般数据保存的方式有两种
文件保存数据库保存
在数据保存的过程中需要对数据完成去重操作所有需要使用 redis 中的 set 数据类型完成去重。
1.CSV文件存储
1.1 什么是csv
通俗直白的说就是一个普通文件里面的内容是每一行中的数据用逗号分隔然后文件后缀为 csv。 1.2 python 对 csv 文件进行读写操作
写入列表数据到 csv 文件
import csvheaders[班级,姓名,性别,手机号,qq]rows [[21级Python, 小王, 男, 13146060xx1, 123456xx1],[23级Python, 小李, 男, 13146060xx2, 123456xx2],[24级Python, 小赵, 女, 13146060xx3, 123456xx3],[25级Python, 小红, 女, 13146060xx4, 123456xx4],
]with open(test.csv,w)as f:# 创建一个csv的writer对象这样才能够将写入csv格式数据到这个文件f_csvcsv.writer(f)# 写入一行我们用第一行当做表头f_csv.writerow(headers)# 写入多行当做数据f_csv.writerows(rows)
写入字典数据到 csv 文件
import csvrows [{class_name: 21级Python,name: 小王,gender: 男,phone: 13146060xx1,qq: 123456xx1},{class_name: 23级Python,name: 小李,gender: 男,phone: 13146060xx2,qq: 123456xx2},{class_name: 25级Python,name: 小赵,gender: 女,phone: 13146060xx3,qq: 123456xx3},{class_name: 25级Python,name: 小红,gender: 女,phone: 13146060xx4,qq: 123456xx4},
]with open(test2.csv,w)as f:# 创建一个csv的DictWriter对象这样才能够写入csv格式数据到这个文件f_csvcsv.DicWriter(f,[class_name,name,gender,phone,qq])# 写入一行我们用第一行当做表头f_csv.writeheader()# 写入多行当做数据f_csv.writerows(rows)
读取 csv 文件
import csvwith open(test.csv)as f:# 创建一个reader对象迭代时能够提取到每一行包括表头f_csvcsv.reader(f)for row in f_csv:print(type(row),row)
读取 csv 文件内容并封装为字典
import csvwith open(test1.csv) as f:# 创建一个reader对象迭代时能够提取到每一行包括表头f_csvcsv.DictReader(f)for row in f_csv:# print(type(row),row)print(row.get(class_name),row.get(name),row.get(phone),row.get(qq)
1.3 b站数据采集
目标网站地址https://search.bilibili.com/video?keyword篮球from_sourcewebtop_searchspm_id_from333.1007search_source5
import csvimport requestsclass SaveVideoInfo():def __init__(self):self.urlhttps://api.bilibili.com/x/web-interface/wbi/search/type?category_idsearch_typevideoad_resource5654__refresh__true_extracontextpage{}page_size42pubtime_begin_s0pubtime_end_s0from_sourcefrom_spmid333.337platformpchighlight1single_column0keyword%E7%AF%AE%E7%90%83qv_idUqmKhHZFJGpXJFFFysVbJhBLO4zYWxY2source_tag3gaia_vtokendynamic_offset0web_location1430654w_ridc58c1bee2f07bcb5250d3833e77c22fcwts1740882524self.headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36,Cookie:header_theme_versionCLOSE; DedeUserID1298980584; DedeUserID__ckMd55e3b2340397bdf6e; enable_web_pushDISABLE; buvid3E09C3995-A4E5-1427-8C75-E1AB8023027295670infoc; rpdid|(k)~YuRY)RR0Ju~u|YYumYu; FEED_LIVE_VERSIONV_WATCHLATER_PIP_WINDOW3; fingerprintc6a73c0f0dda55fe0746058e948b8654; buvid_fp_plainundefined; buvid_fpc6a73c0f0dda55fe0746058e948b8654; hit-dyn-v21; home_feed_column4; buvid4D4D31387-5D1E-A689-10B9-E17B2599A15351637-024090611-3XXTIiLzW/2j4Tgy4In/g%3D%3D; enable_feed_channelDISABLE; b_nut100; _uuidA779410D4-3F32-5B8C-872D-22A37674D73C07883infoc; browser_resolution1280-632; CURRENT_QUALITY80; bp_t_offset_12989805841036726571777392640; b_lsid7F947BD3_19554A85E19; bili_ticketeyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDExNDEyNzUsImlhdCI6MTc0MDg4MjAxNSwicGx0IjotMX0.aIhl_FfT5aPDRq54w2lQD8qA76uyoqdCY6LRlo-xS5M; bili_ticket_expires1741141215; SESSDATAd3ec22cb%2C1756434076%2C4b232%2A32CjC1HLgvdM4y8bKAGeIfrMY5cm4LWa-65-GDqQyHmQVBvADeCGns4u2YfIICt5-J9ckSVnVOdXBWQU9xZi1NUFBLNHNkMGk2WExrQk5aYXp6bXNNVWlFNTZIdUM1UjB2M3oyNXE4NzZFMEVSTWpJSm84QXZBekp0RG4tQi1BX3I3MGZmX2tLOUdRIIEC; bili_jct8c27e9ac7fb3ae6ed9c99ffc500d6c4c; CURRENT_FNVAL2000; sid86toff3u}def save(self):with open(test_b.csv,w,newline)as f:header [author, tag, arcurl]f_csvcsv.DictWriter(f,fieldnamesheader)f_csv.writeheader()for page in range(1,6):resrequests.get(self.url.format(page),headersself.headers).json()for i in res[data][result]:itemdict()item[author]i[author]item[tag]i[tag]item[arcurl]i[arcurl]# print(item)f_csv.writerow(item)sSaveVideoInfo()
s.save()
2.JSON文件存储
2.1 json数据格式介绍
JSON 全称为 JavaScript Object Notation ,也就是 JavaScript 对象标记它通过对象和数组的组合来表示数据构造简洁但是结构化程度非常高是一种轻量级的数据交换格式。
常见的 json 数据格式如下
[{name: Bob, gender: male, birthday: 1992-10-18 }, { name: Selina, gender: female, birthday: 1995-10-18 }
]
由中括号包围的就相当于列表类型列表中的每一个元素可以是任意类型这个示例中它是字典类型由大括号包围。
json 可以由以上两种形式自由组合而成可以无限次嵌套结构清晰是数据交换的极佳方式。
2.2 python 中的 json 模块
方法作用json.dumps()把 python 对象转换成 json 对象生成的是字符串json.dump()用于将 dict 类型的数据转成 str ,并写入到 json 文件中json.loads()将 json 字符串解码成 python 对象json.load()用于从 json 文件中读取数据
2.3 爬虫案例——4399网站游戏信息采集
目标地址https://www.4399.com/flash/
import json
import requests
from lxml import etreeclass SaveInfo():def __init__(self):self.urlhttps://www.4399.com/flash/self.headers{user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36}def save(self):with open(data.json,w,encodingutf-8) as f:resrequests.get(self.url,headersself.headers)res.encodinggbk# 数据解析htmletree.HTML(res.text)data_listhtml.xpath(//ul[classn-game cf]/li/a)all_list[]for i in data_list:itemdict()item[title] i.xpath(b/text())[0]item[href]https://www.4399.comi.xpath(href)[0]all_list.append(item)# f.write(json.dumps(all_list))# # 禁止ascii编码f.write(json.dumps(all_list, indent2, ensure_asciiFalse))sSaveInfo()
s.save()
3.MySQL数据库存储
在处理 python web开发或者其他需要频繁进行数据库操作的项目时重复的打开和关闭数据库连接既消费时间也浪费资源。为了解决这个问题我们采用数据库连接池的方式复用已经创建好的连接对象从而无需频繁的开启连接和关闭连接。
3.1 pymysql 的使用
环境准备
安装pymysql
pip install pymysql -i https://pypi.douban.com/simple
创建数据库
create database py_spider charsetutf8;
PyMysql连接
import pymysql# 打开数据库连接
db pymysql.connect(hostlocalhost,userroot,password000000,databasepython_mysql) # 数据库名字# 使用cursor()方法获取操作游标
cursor db.cursor()# 关闭数据库连接
db.close()PyMysql插入
data1,data2,data3 2,孜然,None
# SQL 插入语句
sql INSERT INTO url_data(url_id,url_title, url_author)VALUES (%s,%s,%s)try:# 执行sql语句cursor.execute(sql,(data1,data2,data3))# 提交到数据库执行db.commit()print(成功)
except Exception as e:# 如果发生错误则回滚db.rollback()print(f失败{e})
PyMysql查询
# SQL 查询语句
sql SELECT * FROM url_data WHERE url_id 1
try:# 执行SQL语句cursor.execute(sql)# 获取所有记录列表results cursor.fetchall()print(results)
except:print(Error: unable to fetch data)PyMysql更新
# 更新
UPDATE url_data SET url_title 番茄酱 WHERE url_id 1;PyMysql删除
# 删除
DELETE FROM url_data WHERE url_title 番茄酱案例 网站地址搜索 | 腾讯招聘 import requests
import pymysql
# 网址https://careers.tencent.com/search.html?queryat_1,at_2keywordpython
class SaveTxWork():def __init__(self):self.url https://careers.tencent.com/tencentcareer/api/post/Query?timestamp1740891587275countryIdcityIdbgIdsproductIdcategoryIdparentCategoryIdattrId1,2keywordpythonpageIndex{}pageSize10languagezh-cnareacnself.headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36}self.dbpymysql.connect(hostlocalhost,userroot,password123456,dbpy_spider)self.cursorself.db.cursor()def get_work_info(self):for page in range(1,15):resrequests.get(self.url.format(page),headersself.headers).json()print(f正在抓取第{page}页面)yield res[Data][Posts]def create_table(self):sqlcreate table if not exists tx_work(id int primary key auto_increment,work_name varchar(100) not null,country_name varchar(100),city_name varchar(100),work_desc text);try:self.cursor.execute(sql)print(数据表创建成功)except Exception as e:print(数据表创建失败,e)def insert_table(self,*args):sqlinsert into tx_work(id,work_name,country_name,city_name,work_desc) values (%s,%s,%s,%s,%s)try:self.cursor.execute(sql,args)self.db.commit()print(数据插入成功)except Exception as e:self.db.rollback() # 回滚事务print(数据插入失败:,e)def main(self):self.create_table()all_work_generator_objectself.get_work_info()work_id0for work_info_list in all_work_generator_object:if work_info_list:for work_info in work_info_list:work_name work_info[RecruitPostName]country_name work_info[CountryName]city_name work_info[LocationName]work_desc work_info[Responsibility]self.insert_table(work_id,work_name,country_name,city_name,work_desc)else:print(数据为空)continue# 任务完成后关闭数据库连接self.db.close()if __name____main__:tx_workSaveTxWork()tx_work.main()3.2 DBUtils 的简单使用
安装命令
pip install DBUtils
导入模块
from dbutils.pooled_db import PooledDB
创建数据库连接池
使用 PooledDB 创建数据库连接池连接池使用了一种新的 DB-API 连接方式可以维护活动连接的池。当需要数据库连接时直接从池中获取连接对象。完成操作后将无需使用的连接对象返回到池中。无需频繁的关闭和开启连接。
pool PooledDB(creatorpymysql, # 使用链接数据库的模块maxconnections6,# 连接池允许的最大连接数0和None表示无限制连接数mincached2, # 初始化时连接池中至少创建的空闲的链接0表示不创建maxcached2, # 链接池中最多闲置的链接0和None不限制maxshared3, # 链接池中最多共享的链接数量0和None表示全部共享。PS无用因为pymysql和mysqldb的模块都不支持共享链接blockingTrue, # 连接池中如果没有可用链接后是否阻塞等待。False,不等待直接报错True等待直到有可用链接再返回。host127.0.0.1,port3306,userusername,passwordpassword,databasedatabase,charsetutf8
)使用数据库连接池
连接池对象创建成功后可以从此对象中获取链接
# 你可以使用这个游标进行所有的常规的数据库交互操作
db_cursorpool.connection().cursor()
查询示例
import pymysql
from dbutils.pooled_db import PooledDB# 创建连接池对象
poolPooledDB(creatorpymysql, # 使用链接数据库的模块maxconnections6, # 连接池允许的最大连接数0和None表示无限制连接数mincached2, # 初始化时连接池中至少创建的空闲的链接0表示不创建maxcached5, # 连接池中最多闲置的链接0和None不限制maxshared3, # 链接池中最多共享的链接数量0和None表示全部共享blockingTrue, # 连接池中如果没有可用的链接后是否阻塞等待。False不等待直接报错等待直到有可用链接再返回。host127.0.0.1,port3306,userroot,password123456,databasepy_spider,charsetutf8
)# 获取数据库连接
connpool.connection()# 获取游标
cursorconn.cursor()# 执行查询操作
cursor.execute(SELECT * FROM tx_work)# 获取查询结果
resultcursor.fetchall()# 打印结果
print(result)# 关闭游标和连接
总结
数据库连接池是一种节省资源并提高效率的方法特别是在处理大量数据库操作的 web 程序和网络应用程序中。创建连接池对象并获取到游标后游标的使用方式与 pymysql 中的游标使用方法一致在后面的并发爬虫中我们会利用数据库连接池完成数据的并发读写操作。 4.MongoDB数据库存储
MongoDB 是由 C语言编写的非关系型数据库是一个基于分布式文件存储的开源数据库系统其内容存储形式类似 JSON 对象它的字段值可以包含其他文档、数组及文档数组。
常用命令
查询数据库show dbs使用数据库use 库名查看集合show tables /show collections查询表数据db.集合名.find()删除表db.集合名.drop()
mongoDB在python中的基础使用
连接 MongoDB 时我们需要使用 PyMongo 库里面的 MongoClient。一般来说传入 MongoDB 的 IP 及端口即可其中第一个参数为地址 host 第二个参数为端口 port 如果不给它传递参数默认是27017。
import pymongo# 0.连接到 MongoDB 服务器
clientpymogo.MongoClient(hostlocalhost,port27017)# 1.创建 SPIDER 数据库
db client[SPIDER]# 3.在 SPIDER 中创建集合
collection db[spider_1]# 5.插入一条示例数据
data1 {name: example,value: 42
}data2 {name: example1,value: 43
}insert_result collection.insert_many([data1, data2])# 2.查看有什么数据库
print(所有数据库:, client.list_database_names())# 4.查看 SPIDER 中有什么集合
print(SPIDER 数据库中的集合:, db.list_collection_names())# 6.查看 spider_1 中的数据
print(spider_1 集合中的数据:)
for i in collection.find():print(i)# 7.删除一条数据
delete_result collection.delete_one({name: example})
print(f删除了 {delete_result.deleted_count} 条文档)# 再次查看 spider_1 中的数据
print(删除数据后 spider_1 集合中的数据:)
for i in collection.find():print(i)# 8.更新数据
# 假设我们要将 name 为 example1 的文档的 value 字段更新为 50
update_filter {name: example1}
update_data {$set: {value: 50}}
update_result collection.update_one(update_filter, update_data)print(f更新了 {update_result.modified_count} 条文档)# 再次查看更新后 spider_1 中的数据
print(更新数据后 spider_1 集合中的数据:)
for i in collection.find():print(i)
案例——爱奇艺视频数据信息 获取到爱奇艺视频数据信息标题、播放地址、简介 目标地址内地电视剧大全-好看的内地电视剧排行榜-爱奇艺 import pymongo
import requestsclass AiqiyiInfo():def __init__(self):self.mongo_clientpymongo.MongoClient(hostlocalhost,port27017)self.collectionself.mongo_client[py_spider][AiQiYi]self.urlhttps://pcw-api.iqiyi.com/search/recommend/list?channel_id2data_type1mode11page_id{}ret_num48session101d987ca7d145e4a9d60b073b02d96ethree_category_id15;mustself.headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36}def get_movie_info(self):for i in range(1,15):print(f正在爬取第{i}页)resrequests.get(self.url.format(i),headersself.headers).json()[data][list]yield resdef parse_movie_info(self,res):itemdict()for vedio_list in res:if vedio_list:for vedio_info in vedio_list:item[name]vedio_info [name]item[playUrl]vedio_info [playUrl]item[description]vedio_info [description]try:self.save(item)except Exception as e:print(保存失败,e)print(保存成功)def save(self,item):if _id in item:del item[_id] # 如果存在删除该字段让 MongoDB 自动生成唯一 _idself.collection.insert_one(item)def main(self):resself.get_movie_info()self.parse_movie_info(res)# 程序完成后关闭数据库链接self.mongo_client.close()if __name____main__:aAiqiyiInfo()a.main() 5.数据去重
在抓取数据的过程中可能因为网络原因造成爬虫程序崩溃退出如果重新启动爬虫的话会造成数据入库重复的问题。下面我们使用redis来进行数据去重。
安装redis
在windows中安装redis的教程Window下Redis的安装和部署详细图文教程Redis的安装和可视化工具的使用_redis安装-CSDN博客
pip install redis -i https://pypi.douban.com/simple
项目需求以及思路分析 目标网址芒果TV 思路分析
首先判断当前网站上的数据是否为动态数据如果为动态数据则使用浏览器抓包工具获取数据接口当前接口地址如下https://pianku.api.mgtv.com/rider/list/pcweb/v3?allowedRC1platformpcwebchannelId2pn1pc80hudong1_support10000000kind19area10yearallchargeInfoa1sortc2当获取到数据后对数据进行哈希编码因为每一个哈希值是唯一的所以可以利用这一特性判断数据是否重复。将获取的数据存储到mongodb数据库中在调用保存方法之前先调用哈希方法将数据转为哈希并保存到redis中再判断当前获取的数据的哈希是否存在于redis数据库如果存在则不保存反之亦然。
6.图片的存储
案例王者荣耀游戏壁纸 目标网址https://pvp.qq.com/web201605/wallpaper.shtml import requests
import pymongo
import redis
import hashlibclass MangGuoInfo():def __init__(self):self.mongo_clientpymongo.MongoClient(hostlocalhost,port27017)self.collectionself.mongo_client[MangGuo_TV][movie_info]self.redis_clientredis.Redis()self.urlhttps://pianku.api.mgtv.com/rider/list/pcweb/v3?allowedRC1platformpcwebchannelId2pn{}pc80hudong1_support10000000kind3003area10yearallfeatureallchargeInfoa1sortc2self.headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36}def get_movie_info(self):for i in range(1,15):print(f正在爬取第{i}页)resrequests.get(urlself.url.format(i),headersself.headers).json()yield res[data][hitDocs]def parse_movie_info(self,res):for movie_list in res:if movie_list:itemdict()for movie_info in movie_list:item[title]movie_info[title]item[subtitle]movie_info[subtitle]item[story]movie_info[story]self.save(item)staticmethoddef get_md5(value):# md5方法只能接收字节数据# 计算哈希值哈希值是唯一的哈希值长度为32位md5_hashhashlib.md5(str(value).encode(utf-8)).hexdigest()return md5_hashdef save(self,item):valueself.get_md5(item)# 当前返回的是redis是否成功保存md5数据保存成功result1保存失败result0resultself.redis_client.sadd(movie:filter,value)if result:# 确保插入的数据没有 _id 字段item.pop(_id, None)self.collection.insert_one(item)print(item)print(保存成功)else:print(数据重复...)def main(self):resself.get_movie_info()self.parse_movie_info(res)if __name____main__:mMangGuoInfo()m.main()