鱼C论坛

 找回密码
 立即注册
查看: 1005|回复: 17

[已解决]爬虫存储数据到MySQL

[复制链接]
发表于 2023-6-4 15:44:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请问大佬们,这个代码哪里错了
import requests
import logging
import pymongo
import pymysql

index_url = 'https://spa1.scrape.center/api/movie/?limit=10&offset={}'
detail_url = 'https://spa1.scrape.center/api/movie/{}/'
header = {
   "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}
logging.basicConfig(level=logging.INFO,format = '%(asctime)s - %(levelname)s: %(message)s')


#连接MySQL数据库
#初始化
conn = pymysql.Connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456a'
)
cursor = conn.cursor()






#发起请求
def scrapy_api(index_url):
    logging.info('正在爬取{}...'.format(index_url))
    try:
        response = requests.get(url=index_url,headers=header,verify=False)
        if response.status_code == 200:
            return response.json()
        logging.error('爬取代码为{},爬取{}失败'.format(response.status_code,index_url))
    except requests.RequestException:
        logging.error('爬取{}失败'.format(index_url),exc_info=True)

#爬取列表页
def scrape_index(page):
    page_url = index_url.format(10*(page-1))
    return scrapy_api(page_url)

#拼接url并发起请求
def scrape_detail(id):
    url = detail_url.format(id)
    return scrapy_api(url)



#保存2:MySQL
def save_data(data):
    sql = 'INSERT INTO movies(id,name,score) values (%s,%s,%s)'
    try:
        cursor.execute(sql, (data.get('id'),data.get('name'),data.get('score')))
        conn.commit()
    except:
        conn.rollback()
    conn.close()

def main():
    for page in range(1,3):
        index_data = scrape_index(page)
        for item in index_data.get('results'):
            id = item.get('id')
            detail_data = scrape_detail(id)
            logging.info('detail data {}'.format(detail_data))
            save_data(detail_data)
            logging.info('保存成功')



if __name__ == '__main__':
    main()
最佳答案
2023-6-4 15:46:14
您的代码中有一个明显的问题,就是在  save_data  函数中,您关闭了数据库连接。在您的代码中,这个函数会在每次爬取和保存电影详情信息时都被调用,所以在第一次调用后,数据库连接就会被关闭,之后的数据库操作都会失败。

如果您想要在所有的电影详情信息都爬取和保存后再关闭数据库连接,您可以把  conn.close()  这行代码移到  main  函数中,比如在所有循环结束后。

修改后的代码如下:
def save_data(data):
    sql = 'INSERT INTO movies(id,name,score) values (%s,%s,%s)'
    try:
        cursor.execute(sql, (data.get('id'),data.get('name'),data.get('score')))
        conn.commit()
    except:
        conn.rollback()

def main():
    for page in range(1,3):
        index_data = scrape_index(page)
        for item in index_data.get('results'):
            id = item.get('id')
            detail_data = scrape_detail(id)
            logging.info('detail data {}'.format(detail_data))
            save_data(detail_data)
            logging.info('保存成功')
    conn.close()

if __name__ == '__main__':
    main()

另外,有两个小问题可能也会引发错误。首先,我注意到您使用了 pymongo 模块,但是在这段代码中并没有实际用到它,因此,如果没有必要,您可以考虑删除这个导入。其次,您没有在连接到MySQL数据库时指定数据库的名称,这可能会导致在插入数据时出错。您可以在  pymysql.Connect  中添加一个  db='database_name'  的参数, database_name  是您要连接的数据库的名称。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-6-4 15:45:59 | 显示全部楼层
本帖最后由 歌者文明清理员 于 2023-6-4 15:51 编辑

这段代码缺少了连接 MongoDB 数据库的初始化和连接过程,可能会导致在爬取数据时无法将数据存储到 MongoDB 数据库中。

如果需要连接 MongoDB 数据库,可以参考以下的代码:

python
client = pymongo.MongoClient('mongodb://localhost:27017/')
db = client['test'] # 创建一个数据库实例
collection = db['movies'] # 创建一个用于存储电影数据的集合
然后在保存数据的函数 save_data 中,可以将数据存储到 MongoDB 数据库中,示例代码如下:

python
# 保存数据到 MongoDB
def save_data(data):
    result = collection.insert_one(data)
    if result.acknowledged:
        logging.info('保存成功')
    else:
        logging.error('保存失败')
需要注意的是,在保存数据之前,你需要从爬虫获取到的数据中提取出需要保存的数据,例如电影名称、评分等信息。另外,在程序结束之前,需要关闭数据库连接,以释放资源,示例代码如下:

python
# 关闭连接
client.close()

以下是添加了 MongoDB 数据库连接和修改 save_data 函数后的代码:

python
import requests
import logging
import pymongo
import pymysql

index_url = 'https://spa1.scrape.center/api/movie/?limit=10&offset={}'
detail_url = 'https://spa1.scrape.center/api/movie/{}/'
header = {
   "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}
logging.basicConfig(level=logging.INFO,format = '%(asctime)s - %(levelname)s: %(message)s')


# 连接 MySQL 数据库
conn = pymysql.Connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456a'
)
cursor = conn.cursor()

# 连接 MongoDB 数据库
client = pymongo.MongoClient('mongodb://localhost:27017/')
db = client['test'] # 创建一个数据库实例
collection = db['movies'] # 创建一个用于存储电影数据的集合


# 发起请求
def scrapy_api(index_url):
    logging.info('正在爬取{}...'.format(index_url))
    try:
        response = requests.get(url=index_url,headers=header,verify=False)
        if response.status_code == 200:
            return response.json()
        logging.error('爬取{}失败,状态码为{}'.format(index_url,response.status_code))
    except requests.RequestException:
        logging.error('爬取{}失败'.format(index_url),exc_info=True)

# 爬取列表页
def scrape_index(page):
    page_url = index_url.format(10*(page-1))
    return scrapy_api(page_url)

# 拼接url并发起请求
def scrape_detail(id):
    url = detail_url.format(id)
    return scrapy_api(url)

# 保存数据到 MySQL
def save_data_by_mysql(data):
    sql = 'INSERT INTO movies(id,name,score) values (%s,%s,%s)'
    try:
        cursor.execute(sql, (data.get('id'),data.get('name'),data.get('score')))
        conn.commit()
        logging.info('MySQL 数据库保存成功')
    except:
        conn.rollback()
        logging.error('MySQL 数据库保存失败')

# 保存数据到 MongoDB
def save_data_by_mongodb(data):
    result = collection.insert_one(data)
    if result.acknowledged:
        logging.info('MongoDB 数据库保存成功')
    else:
        logging.error('MongoDB 数据库保存失败')

def main():
    for page in range(1,3):
        index_data = scrape_index(page)
        for item in index_data.get('results'):
            id = item.get('id')
            detail_data = scrape_detail(id)
            logging.info('detail data {}'.format(detail_data))

            # 选择某种方式保存数据
            save_data_by_mysql(detail_data)
            # save_data_by_mongodb(detail_data)

    # 关闭连接
    conn.close()
    client.close()

if __name__ == '__main__':
    main()
在函数中添加了 save_data_by_mongodb 函数用于将数据存储到 MongoDB,以 save_data_by_mysql 函数用于将数据存储到 MySQL。同时,程序结束后需要关闭数据库连接以释放资源。

需要注意的是,为了确保代码的可读性,建议将 Mongo 和 Mysql 的存储分开写,不要在一个函数中混写,这样更有利于代码的维护。

代码的维护:

代码的维护是指在软件开发过程中,在项目上线后,对代码进行不断的修改、调整、更新和优化,以保证软件能够持续稳定的运行和向用户提供良好的体验。代码的维护包括以下内容:

  • Bug 修复:当软件出现问题或异常时,需要对代码进行修复,以使软件能够正常运行。
  • 功能调整:当软件的功能不符合用户需求或市场变化时,需要对代码进行调整以添加、优化或删除功能。
  • 性能优化:当软件的性能不佳时,需要对代码进行优化,以提高软件的运行速度和响应效率。
  • 安全加固:当软件面临安全威胁时,需要对代码进行加固,以防止黑客攻击、数据泄露等安全问题。
  • 文档编写:需要对代码进行文档编写,以便其他开发者可以更好地理解代码结构和运行逻辑,以便后续的维护和升级。
  • 通过对代码的维护,可以确保软件能够持续的运行,并向用户提供更好的服务体验。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:46:14 | 显示全部楼层    本楼为最佳答案   
您的代码中有一个明显的问题,就是在  save_data  函数中,您关闭了数据库连接。在您的代码中,这个函数会在每次爬取和保存电影详情信息时都被调用,所以在第一次调用后,数据库连接就会被关闭,之后的数据库操作都会失败。

如果您想要在所有的电影详情信息都爬取和保存后再关闭数据库连接,您可以把  conn.close()  这行代码移到  main  函数中,比如在所有循环结束后。

修改后的代码如下:
def save_data(data):
    sql = 'INSERT INTO movies(id,name,score) values (%s,%s,%s)'
    try:
        cursor.execute(sql, (data.get('id'),data.get('name'),data.get('score')))
        conn.commit()
    except:
        conn.rollback()

def main():
    for page in range(1,3):
        index_data = scrape_index(page)
        for item in index_data.get('results'):
            id = item.get('id')
            detail_data = scrape_detail(id)
            logging.info('detail data {}'.format(detail_data))
            save_data(detail_data)
            logging.info('保存成功')
    conn.close()

if __name__ == '__main__':
    main()

另外,有两个小问题可能也会引发错误。首先,我注意到您使用了 pymongo 模块,但是在这段代码中并没有实际用到它,因此,如果没有必要,您可以考虑删除这个导入。其次,您没有在连接到MySQL数据库时指定数据库的名称,这可能会导致在插入数据时出错。您可以在  pymysql.Connect  中添加一个  db='database_name'  的参数, database_name  是您要连接的数据库的名称。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:50:42 | 显示全部楼层
isdkz 发表于 2023-6-4 15:46
您的代码中有一个明显的问题,就是在  save_data  函数中,您关闭了数据库连接。在您的代码中,这个函数会 ...

好的,感谢感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:51:24 | 显示全部楼层
哈岁NB 发表于 2023-6-4 15:50
好的,感谢感谢

我先回答的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:51:41 | 显示全部楼层
歌者文明清理员 发表于 2023-6-4 15:45
这段代码缺少了连接 MongoDB 数据库的初始化和连接过程,可能会导致在爬取数据时无法将数据存储到 MongoDB  ...

好的,感谢感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:51:47 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:52:08 | 显示全部楼层
哈岁NB 发表于 2023-6-4 15:51
好的,感谢感谢

完了,不小心被审核了……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:53:06 | 显示全部楼层

草,被审核了,gpt:
代码的维护是指在软件开发过程中,在项目上线后,对代码进行不断的修改、调整、更新和优化,以保证软件能够持续稳定的运行和向用户提供良好的体验。代码的维护包括以下内容:

Bug 修复:当软件出现问题或异常时,需要对代码进行修复,以使软件能够正常运行。

功能调整:当软件的功能不符合用户需求或市场变化时,需要对代码进行调整以添加、优化或删除功能。

性能优化:当软件的性能不佳时,需要对代码进行优化,以提高软件的运行速度和响应效率。

安全加固:当软件面临安全威胁时,需要对代码进行加固,以防止HEI KE攻击、数据泄露等安全问题。

文档编写:需要对代码进行文档编写,以便其他开发者可以更好地理解代码结构和运行逻辑,以便后续的维护和升级。

通过对代码的维护,可以确保软件能够持续的运行,并向用户提供更好的服务体验。

完啦~8bq啦~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:55:45 | 显示全部楼层

因为想存到mysql,您回答MongoDB,所以就不能给您了,不好意思
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:56:23 | 显示全部楼层
哈岁NB 发表于 2023-6-4 15:55
因为想存到mysql,您回答MongoDB,所以就不能给您了,不好意思

你也不能给我,因为没注意敏感词被审核了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:57:11 | 显示全部楼层
歌者文明清理员 发表于 2023-6-4 15:56
你也不能给我,因为没注意敏感词被审核了

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 15:57:57 | 显示全部楼层

“HEI KE”
你回复试试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:59:14 | 显示全部楼层

黑客
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 15:59:38 | 显示全部楼层

被审核了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 16:03:06 | 显示全部楼层
isdkz 发表于 2023-6-4 15:46
您的代码中有一个明显的问题,就是在  save_data  函数中,您关闭了数据库连接。在您的代码中,这个函数会 ...

请问这个代码要是想把爬取到的JSON字符串所有的键值都保存到数据库里,只能一个一个创建和插入吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-4 16:33:34 | 显示全部楼层
哈岁NB 发表于 2023-6-4 16:03
请问这个代码要是想把爬取到的JSON字符串所有的键值都保存到数据库里,只能一个一个创建和插入吗

如果您想要将爬取到的 JSON 数据的所有键值都保存到数据库中,确实需要确保数据库中的每个字段都有对应的 JSON 键值。然而,有些方法可以简化此过程。

在 Python 中,您可以使用 dictionary 的 keys 方法来获取 JSON 数据的所有键,然后使用这些键来构建插入语句。假设 JSON 数据为  data ,那么  data.keys()  就会返回一个包含所有键的列表。这个列表可以用于构建 SQL 插入语句的字段部分。同样, data.values()  可以返回一个包含所有值的列表,用于构建插入语句的值部分。

这是一个简单的示例:
def save_data(data):
    keys = ', '.join(" " + str(x) + " " for x in data.keys())
    values = ', '.join("'" + str(x) + "'" for x in data.values())
    sql = "INSERT INTO {table} ({keys}) VALUES ({values});".format(table="movies", keys=keys, values=values)
    try:
        cursor.execute(sql)
        conn.commit()
    except Exception as e:
        conn.rollback()
        print('Insert error:', e)

注意,这个示例假设您的 JSON 数据(即  data )是一个字典,并且字典的每个键都与数据库中的某个字段相对应。如果这不是情况,那么您可能需要对数据进行进一步的处理。

此外,这个示例将所有值都视为字符串,然后在 SQL 语句中用引号括起来。如果您的 JSON 数据包含非字符串类型的值,那么您可能需要对每个值的处理方法进行更精细的控制,以确保它们在 SQL 语句中的格式是正确的。

最后,注意 SQL 注入的风险。在这个示例中,我们直接将数据的键和值插入到 SQL 语句中。如果这些数据是用户提供的,那么它们可能包含恶意的 SQL 代码。在实践中,您应该始终对这些值进行适当的清理或转义,或者使用参数化的查询来防止 SQL 注入。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 16:36:33 | 显示全部楼层
isdkz 发表于 2023-6-4 16:33
如果您想要将爬取到的 JSON 数据的所有键值都保存到数据库中,确实需要确保数据库中的每个字段都有对应的 ...

好的,感谢感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-22 23:34

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表