2022年 11月 4日

超详细解析:使用Python数据采集,并将数据保存到数据库中

在本文中以爬取某网中每个房型房源信息,并且按照房源用途分别保存到不同表中为例。

首先导入爬虫需要的selenuim模块、休眠要用的time模块、连接数据库要用的pymysql模块,并且连接数据库。

host=你本机的ip地址,localhost就是本机的ip地址

user=连接MySQL的用户名

password=连接MySQL的密码

db=操作的数据库名称

cursor为一个对象,如果需要对我们定义的数据库进行操作,直接就对cursor操作即可。

如果想要把爬取下来的数据保存到数据库表中,就必须要先创建表结构,比如在下方最后三行代码中,创建了三张表用于后续保存爬取下来的数据

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from selenium import webdriver
  4. from time import sleep
  5. import pymysql
  6. # 连接数据库
  7. conn = pymysql.connect(host='localhost',user='root',password='123456',db='db')
  8. cursor = conn.cursor()
  9. #执行一个SQL语句
  10. cursor.execute('create table if not exists bk_zz(name varchar(255),sale varchar(255),type varchar(255),local varchar(255),local1 varchar(255),huxing varchar(255),jianmian varchar(255),small_price varchar(255),big_price varchar(255),subway varchar(255),shopping varchar(255))')
  11. cursor.execute('create table if not exists bk_bs(name varchar(255),sale varchar(255),type varchar(255),local varchar(255),local1 varchar(255),huxing varchar(255),jianmian varchar(255),small_price varchar(255),big_price varchar(255),subway varchar(255),shopping varchar(255))')
  12. cursor.execute('create table if not exists bk_qt(name varchar(255),sale varchar(255),type varchar(255),local varchar(255),local1 varchar(255),huxing varchar(255),jianmian varchar(255),small_price varchar(255),big_price varchar(255),subway varchar(255),shopping varchar(255))')

cursor用来执行命令的方法:

callproc(self, procname, args):用来执行存储过程,接收的参数为存储过程名和参数列表,返回值为受影响的行数

execute(self, query, args):执行单条sql语句,接收的参数为sql语句本身和使用的参数列表,返回值为受影响的行数

executemany(self, query, args):执行单挑sql语句,但是重复执行参数列表里的参数,返回值为受影响的行数

nextset(self):移动到下一个结果集

cursor用来接收返回值的方法:

fetchall(self):接收全部的返回结果行.

fetchmany(self, size=None):接收size条返回结果行.如果size的值大于返回的结果行的数量,则会返回cursor.arraysize条数据.

fetchone(self):返回一条结果行.

scroll(self, value, mode=’relative’):移动指针到某一行.如果mode=’relative’,则表示从当前所在行移动value条,如果mode=’absolute’,则表示从结果集的第一 行移动value条.

 以下是该案例下爬取数据的代码,可根据实际情况去更改。

  1. # 实现反检测
  2. from selenium.webdriver import ChromeOptions
  3. option = ChromeOptions()
  4. option.add_experimental_option('excludeSwitches',['enable-automation'])
  5. # 实例化一个浏览器对象
  6. bro = webdriver.Chrome(executable_path='./chromedriver',options=option)
  7. # 对贝壳发起请求
  8. bro.get('https://bj.ke.com/')
  9. # 定位搜索按钮,并点击
  10. bro.find_element_by_xpath('//*[@id="beike"]/div[1]/div/div[2]/div/ul/li[2]/a').click()
  11. sleep(2)
  12. for x in range(10):
  13. # 下拉页面
  14. bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
  15. sleep(5)
  16. # 解析页面
  17. li_list = bro.find_elements_by_xpath('/html/body/div[6]/ul[2]/li')
  18. sleep(1)
  19. for li in li_list:
  20. goods = li.text.split('\n')
  21. # print(goods)
  22. if '新房顾问' in goods[4]:
  23. del goods[4]
  24. for z,y in enumerate(goods):
  25. if y == '关注':
  26. del goods[z]
  27. # print(goods)
  28. a = goods[1].split(' ')
  29. # print(a)
  30. # 获取小区名称
  31. name = a[0]
  32. # 获取售卖情况
  33. sale = a[1]
  34. # 获取房屋类型
  35. house = a[2]
  36. b = goods[2].replace(',','.').split('/')
  37. print(b)
  38. # 获取所在区
  39. big_add = b[0]
  40. # 获取房屋具体位置
  41. small_add = b[2]
  42. if '户型' not in goods[3]:
  43. goods.insert(3,'户型 暂无户型信息 建面 暂无建面信息')
  44. goods[3] = goods[3].replace(' / ','/').replace('/建',' 建')
  45. c = goods[3].split(' ')
  46. # print(c)
  47. # 获取户型
  48. shape = c[1]
  49. # 获取建面
  50. square = c[3]
  51. """'50000 元/㎡(均价)', '总价1848-2500(万/套)'"""
  52. if '均' not in goods[5]:
  53. goods.insert(5,'暂无均价')
  54. if '总' not in goods[-1]:
  55. goods.append('总价暂无总价')
  56. print(goods)
  57. d = goods[-2].split(' ')
  58. # avg_price = goods[-2][:9]
  59. # print(d)
  60. # 获取均价
  61. avg_price = d[0]
  62. # 获取总价
  63. sum_price = goods[-1][2:].split('(')[0]
  64. e = goods[-3].split(' ')
  65. # print(e)
  66. if '地铁沿线' in e:
  67. e.insert(0, '地铁沿线')
  68. else:
  69. e.insert(0, '无地铁')
  70. if '购物方便' in e:
  71. e.insert(1, '购物方便')
  72. else:
  73. e.insert(1, '无商场')
  74. subway = e[0]
  75. shopping = e[1]
  76. if house == '住宅':
  77. sql = "insert into bk_zz values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  78. param = ((name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping),
  79. (name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping))
  80. cursor.executemany(sql, param)
  81. elif house == '别墅':
  82. sql = "insert into bk_bs values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  83. param = ((name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping),
  84. (name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping))
  85. cursor.executemany(sql, param)
  86. else:
  87. sql = "insert into bk_qt values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  88. param = ((name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping),
  89. (name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping))
  90. cursor.executemany(sql, param)
  91. # 点击翻页
  92. if x == 0:
  93. bro.find_element_by_xpath('/html/body/div[7]/div[2]/a[5]').click()
  94. sleep(3)
  95. elif 1 <= x <= 4:
  96. bro.find_element_by_xpath(f'/html/body/div[7]/div[2]/a[6+{x}]').click()
  97. sleep(3)
  98. else:
  99. bro.find_element_by_xpath(f'/html/body/div[7]/div[2]/a[10]').click()
  100. print(f'第{x+1}页爬取成功')
  101. bro.quit()
  102. # 提交数据,并保存到数据库中
  103. re = cursor.fetchall()
  104. conn.commit()
  105. cursor.close()
  106. conn.close()

如果需要批量的插入数据,就这样做

sql = “insert into bk_zz values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)”

每个值的集合为一个tuple,整个参数集组成一个tuple或者list

param = ((name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping),(name, sale, house, big_add, small_add, shape, square, avg_price, sum_price, subway, shopping))

使用executemany方法来批量的插入数据

n=cursor.executemany(sql,param)

需要注意的是,在所有数据插入成功后,要提交数据并且保存到数据库中!!