案例学python——案例三:豆瓣电影信息入库

时间:2022-09-04 18:01:19

 

闲扯皮
昨晚给高中的妹妹微信讲题,函数题,小姑娘都十二点了还迷迷糊糊。今天凌晨三点多,被连续的警报声给惊醒了,以为上海拉了防空警报,难不成地震,空袭?难道是楼下那个车主车子被堵了,长按喇叭?开窗看看,好像都不是。好鬼畜的警报声,家里也没装报警器啊,莫不成家里煤气漏了?起床循声而查,报警声的确在厨房,听起来也像屋外,开门也没发现啥异样,莫不成真的是煤气表?下面开始排查,开水,断水,发现没啥异样。打开煤气灶,关闭煤气,也没啥。全屋断电也没啥,全屋都断电了只能说报警声的确来自煤气表。翻出燃气公司的客服电话,那头真的是个妹子,电话里报了下情况和地址,燃气公司说四个小时内给回访。半个小时后警报声自动消失了,一个小时后门铃声响,维修工拿着测气表一通测试,反馈结果说煤气表是新的,也没有明处漏气,让我签了字,就撤了。打开窗,埋头继续睡了。复盘发现自己犯了个大错,当时不应该打开煤气灶和热水器测试的燃气的,万一煤气真的泄露,后果,今天估计医院凉凉了,不对应该是焦焦了。家庭安全不可大意,还是太年轻了。早上6点多楼上装修的工人拆墙砸墙的声音,不胜其扰,早点去公司敲代码吧。先是复盘了一下昨天爬豆瓣的一些小问题,顺带简单解决了。不闲扯了,代码复盘Python爬豆瓣Top250 的信息入库。

案例一尝试了爬图之后的快感,案例二尝试了白傻呆的数据库操作,案例三就两者整合一下。起因是昨天刚在博客园看到 一篇爬豆瓣的文章 想着刚好能把文章中爬到的信息入数据库,如果在用java操作数据库

岂不美哉,原谅我习惯于javaWeb开发,因为目前只会java啊。昨天用的Python2.7着实不爽,装了3.7版本。

效果预览:

效果一:项目结构

案例学python——案例三:豆瓣电影信息入库

效果二:数据库信息

案例学python——案例三:豆瓣电影信息入库

效果三:本地存储

案例学python——案例三:豆瓣电影信息入库

思路:第一步:爬取信息  第二步:信息解析   第三步:读写文件    第四步:解析数据入库

准备工作

根据解析字段建立对应的数据库,这点因为 博客:一起学爬虫——通过爬取豆瓣电影top250学习requests库的使用 中已经可以看到爬取后解析相关字段,可能有些字段颗粒度不够,在原有基础上再切割切割就ok啦。

数据库连接配置

dbMysqlConfig.cnf

[dbMysql]
host = localhost
port = 3306
user = root
password = root
db_name = dou_film

封装的DBUtils,中间有些小白的错,在里面栽了几个坑:事务,提交,主键自增啥的。其实就用了一个insert()方法,其他方法的正确性可忽略。

mysqlDBUtils.py

#!/usr/bin/python3
# -*- coding:utf-8 -*-
import pymysql, os, configparser
from pymysql.cursors import DictCursor
from DBUtils.PooledDB import PooledDB class Config(object):
"""
# Config().get_content("user_information")
配置文件里面的参数
[dbMysql]
host = 192.168.1.101
port = 3306
user = root
password = python123
""" def __init__(self, config_filename="dbMysqlConfig.cnf"):
file_path = os.path.join(os.path.dirname(__file__), config_filename)
self.cf = configparser.ConfigParser()
self.cf.read(file_path) def get_sections(self):
return self.cf.sections() def get_options(self, section):
return self.cf.options(section) def get_content(self, section):
result = {}
for option in self.get_options(section):
value = self.cf.get(section, option)
result[option] = int(value) if value.isdigit() else value
return result class BasePymysqlPool(object):
def __init__(self, host, port, user, password, db_name):
self.db_host = host
self.db_port = int(port)
self.user = user
self.password = str(password)
self.db = db_name
self.conn = None
self.cursor = None class MyPymysqlPool(BasePymysqlPool):
"""
MYSQL数据库对象,负责产生数据库连接 , 此类中的连接采用连接池实现
获取连接对象:conn = Mysql.getConn()
释放连接对象;conn.close()或del conn
"""
# 连接池对象
__pool = None def __init__(self, conf_name=None):
self.conf = Config().get_content(conf_name)
super(MyPymysqlPool, self).__init__(**self.conf)
# 数据库构造函数,从连接池中取出连接,并生成操作游标
self._conn = self.__getConn()
self._cursor = self._conn.cursor() def __getConn(self):
"""
@summary: 静态方法,从连接池中取出连接
@return MySQLdb.connection
"""
if MyPymysqlPool.__pool is None:
__pool = PooledDB(creator=pymysql,
mincached=1,
maxcached=20,
host=self.db_host,
port=self.db_port,
user=self.user,
passwd=self.password,
db=self.db,
use_unicode=False,
charset="utf8",
cursorclass=DictCursor)
return __pool.connection() def getAll(self, sql, param=None):
"""
@summary: 执行查询,并取出所有结果集
@param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
@param param: 可选参数,条件列表值(元组/列表)
@return: result list(字典对象)/boolean 查询到的结果集
"""
if param is None:
count = self._cursor.execute(sql)
else:
count = self._cursor.execute(sql, param)
if count > 0:
result = self._cursor.fetchall()
else:
result = False
return result def getOne(self, sql, param=None):
"""
@summary: 执行查询,并取出第一条
@param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
@param param: 可选参数,条件列表值(元组/列表)
@return: result list/boolean 查询到的结果集
"""
if param is None:
count = self._cursor.execute(sql)
else:
count = self._cursor.execute(sql, param)
if count > 0:
result = self._cursor.fetchone()
else:
result = False
return result def getMany(self, sql, num, param=None):
"""
@summary: 执行查询,并取出num条结果
@param sql:查询SQL,如果有查询条件,请只指定条件列表,并将条件值使用参数[param]传递进来
@param num:取得的结果条数
@param param: 可选参数,条件列表值(元组/列表)
@return: result list/boolean 查询到的结果集
"""
if param is None:
count = self._cursor.execute(sql)
else:
count = self._cursor.execute(sql, param)
if count > 0:
result = self._cursor.fetchmany(num)
else:
result = False
return result def insertMany(self, sql, values):
"""
@summary: 向数据表插入多条记录
@param sql:要插入的SQL格式
@param values:要插入的记录数据tuple(tuple)/list[list]
@return: count 受影响的行数
"""
count = self._cursor.executemany(sql, values)
return count def __query(self, sql, param=None):
if param is None:
count = self._cursor.execute(sql)
else:
count = self._cursor.execute(sql, param)
return count def update(self, sql, param=None):
"""
@summary: 更新数据表记录
@param sql: SQL格式及条件,使用(%s,%s)
@param param: 要更新的 值 tuple/list
@return: count 受影响的行数
"""
return self.__query(sql, param) def insert(self, sql, param=None):
"""
@summary: 更新数据表记录
@param sql: SQL格式及条件,使用(%s,%s)
@param param: 要更新的 值 tuple/list
@return: count 受影响的行数
"""
num = self._cursor.execute(sql)
self._conn.commit()
return num def delete(self, sql, param=None):
"""
@summary: 删除数据表记录
@param sql: SQL格式及条件,使用(%s,%s)
@param param: 要删除的条件 值 tuple/list
@return: count 受影响的行数
"""
return self.__query(sql, param) def begin(self):
"""
@summary: 开启事务
"""
self._conn.autocommit(0) def end(self, option='commit'):
"""
@summary: 结束事务
"""
if option == 'commit':
self._conn.commit()
else:
self._conn.rollback() def dispose(self, isEnd=1):
"""
@summary: 释放连接池资源
"""
if isEnd == 1:
self.end('commit')
else:
self.end('rollback')
self._cursor.close()
self._conn.close() if __name__ == '__main__':
mysql = MyPymysqlPool("dbMysql")
sqlAll = "select * from seckill;"
result = mysql.getAll(sqlAll)
print(result)
# 释放资源
mysql.dispose()

爬豆瓣页面数据解析,比较佩服的是里面爬取用的是正则表达式去匹配的,这点只能看个门道,平时用正则表达式都是百度匹配的,测试ok就用了。对原有豆瓣做了一些改动,使其合乎我的想法,虽然想法以后回头看也会诸多问题,先搞出来再说吧。

其实导包,类引入,为难了自己一下下。其他都还算顺利。

douFilm.py

 #coding=utf-8
import requests
import re
import json
import importlib
import os
dbUtils = importlib.import_module('mysqlDBUtils') # 定义图片存储位置
global save_path
save_path = 'D:/doubanfilm' # 创建文件夹
def createFile(file_path):
if os.path.exists(file_path) is False:
os.makedirs(file_path)
# 切换路径至上面创建的文件夹
os.chdir(file_path) def parse_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url, headers=headers)
text = response.text
regix = '<div class="pic">.*?<em class="">(.*?)</em>.*?<img.*?src="(.*?)" class="">.*?div class="info.*?class="hd".*?class="title">(.*?)</span>.*?class="other">' \
'(.*?)</span>.*?<div class="bd">.*?<p class="">(.*?)<br>(.*?)</p>.*?class="star.*?<span class="(.*?)"></span>.*?' \
'span class="rating_num".*?average">(.*?)</span>'
results = re.findall(regix, text, re.S)
mysql = dbUtils.MyPymysqlPool("dbMysql")
for item in results:
filepath = down_image(item[1],headers = headers)
print("文件路径"+filepath)
print(item)
# item[2] 电影主流名字 item[3] 电影别名
film_name = item[2] + ' ' + re.sub('&nbsp;','',item[3])
info = re.sub('&nbsp;','',item[4].strip()).split(":")
# 导演
director = info[1].split('主')[0]
# 主演
print(len(info))
if len(info) > 2:
actor = info[2]
else:
actor = "..."
score_mark = star_transfor(item[6].strip()) + '/' + item[7] + '分'
rank_num = item[0]
print(film_name)
# 写sql 语句
sql = 'insert into film (film_name,director,actor,score_mark,rank_num,filepath) value("' + film_name + '","' + director + '","' + actor + '","' + score_mark + '","' + rank_num + '","'+filepath+'")'
# 执行插入
result = mysql.insert(sql)
yield {
'电影名称' : film_name,
'导演和演员' : director,
'评分': score_mark,
'排名' : rank_num
}
mysql.dispose()
def main():
for offset in range(0, 250, 25):
url = 'https://movie.douban.com/top250?start=' + str(offset) +'&filter='
for item in parse_html(url):
# 将每个条目写入txt
write_movies_file(item) def write_movies_file(str):
with open('douban_film.txt','a',encoding='utf-8') as f:
f.write(json.dumps(str,ensure_ascii=False) + '\n') def down_image(url,headers):
r = requests.get(url,headers = headers)
createFile(save_path)
filepath = save_path +'/'+ re.search('/public/(.*?)$', url, re.S).group(1)
print("下载的海报名字"+filepath)
with open(filepath,'wb') as f:
f.write(r.content)
return filepath
def star_transfor(str):
if str == 'rating5-t':
return '五星'
elif str == 'rating45-t' :
return '四星半'
elif str == 'rating4-t':
return '四星'
elif str == 'rating35-t' :
return '三星半'
elif str == 'rating3-t':
return '三星'
elif str == 'rating25-t':
return '两星半'
elif str == 'rating2-t':
return '两星'
elif str == 'rating15-t':
return '一星半'
elif str == 'rating1-t':
return '一星'
else:
return '无星' if __name__ == '__main__':
main()

一切还算顺利,注释都在代码里写明了,应该比较好理解。运行的时候,直接运行douFilm.py就ok了。项目很简单 gitHub地址:https://github.com/islowcity/doufilm.git

案例学python——案例三:豆瓣电影信息入库的更多相关文章

  1. python爬取豆瓣电影信息数据

    题外话+ 大家好啊,最近自己在做一个属于自己的博客网站(准备辞职回家养老了,明年再战)在家里 琐事也很多, 加上自己 一回到家就懒了(主要是家里冷啊! 广东十几度,老家几度,躲在被窝瑟瑟发抖,) 由于 ...

  2. 利用Python爬取豆瓣电影

    目标:使用Python爬取豆瓣电影并保存MongoDB数据库中 我们先来看一下通过浏览器的方式来筛选某些特定的电影: 我们把URL来复制出来分析分析: https://movie.douban.com ...

  3. Python爬取豆瓣电影top

    Python爬取豆瓣电影top250 下面以四种方法去解析数据,前面三种以插件库来解析,第四种以正则表达式去解析. xpath pyquery beaufifulsoup re 爬取信息:名称  评分 ...

  4. 豆瓣电影信息爬取&lpar;json&rpar;

    豆瓣电影信息爬取(json) # a = "hello world" # 字符串数据类型# b = {"name":"python"} # ...

  5. java 语言实现豆瓣电影信息查询

    豆瓣上面有很多电影,有时候要查看个电影信息,去豆瓣搜下还是很方便的,但是如何通过接口的形式来查看豆瓣电影,这对于很多网站.app其实是非常实用的功能,这里笔者附上一个java实现的豆瓣电影信息获取的代 ...

  6. 零基础爬虫----python爬取豆瓣电影top250的信息(转)

    今天利用xpath写了一个小爬虫,比较适合一些爬虫新手来学习.话不多说,开始今天的正题,我会利用一个案例来介绍下xpath如何对网页进行解析的,以及如何对信息进行提取的. python环境:pytho ...

  7. Python:python抓取豆瓣电影top250

    一直对爬虫感兴趣,学了python后正好看到某篇关于爬取的文章,就心血来潮实战一把吧. 实现目标:抓取豆瓣电影top250,并输出到文件中 1.找到对应的url:https://movie.douba ...

  8. Python抓取豆瓣电影top250&excl;

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:404notfound  一直对爬虫感兴趣,学了python后正好看到 ...

  9. python爬取豆瓣视频信息代码

    目录 一:代码 二:结果如下(部分例子)   这里是爬取豆瓣视频信息,用pyquery库(jquery的python库). 一:代码 from urllib.request import quote ...

随机推荐

  1. Oracle ORA-07445 evaopn2&lpar;&rpar;&plus;128错误问题

    Oracle ORA-07445 evaopn2()+128错误问题 问题描述 Plsql developer执行一段sql报错: 经查alert log详细报错信息为: ORA-07445: exc ...

  2. shell中括号的使用

    在这里我想说的是几种shell里的小括号,大括号结构和有括号的变量,命令的用法,如下: 1.${var} 2.$(cmd) 3.()和{} 4.${var:-string},${var:+string ...

  3. Java调用脚本

    几个参考: java调用shell http://www.cnblogs.com/Seamanm/archive/2010/10/04/1842059.html java程序中调用linux命令    ...

  4. &lpar;七&rpar;shell编程学习

    1.shell程序练习:创建一个dir文件夹,在dir文件夹里再创建一个cd.c文件 首先vim hello.sh 2.shell中的变量定义和引用 (1)变量定义和初始化.shell是弱类型语言(语 ...

  5. 生成Apk遇到的问题

    conversion to dalvik format failed with error 1 android proguard keep Parameterized class

  6. webpack基础&plus;webpack配置文件常用配置项介绍&plus;webpack-dev-server

    一.webpack基础 1.在项目中生成package.json:在项目根目录中输入npm init,根据提示输入相应信息.(也可以不生成package.json文件,但是package.json是很 ...

  7. 【转】iOS-Core-Animation-Advanced-Techniques(三)

    原文: http://www.cocoachina.com/ios/20150105/10827.html 专用图层 复杂的组织都是专门化的--Catharine R. Stimpson 到目前为止, ...

  8. 点击显示子菜单,离开隐藏子菜单(onmouseout下包含a标签的js解决方法)

    <div class="menu">     <a href="javascript:void(0);" id="a_all&quo ...

  9. spring之p命名空间注入

    <bean id="personId" class="com.itheima.f_xml.c_p.Person" p:pname="禹太璞&qu ...

  10. 同步Name到Comment 及 同步 Comment 到Name

    在 PowerDesigner执行命令  Tools->Execute Commands->Edit/Run Scripts 代码一:将Name中的字符COPY至Comment中 Opti ...