在本文中以爬取某网中每个房型房源信息,并且按照房源用途分别保存到不同表中为例。
首先导入爬虫需要的selenuim模块、休眠要用的time模块、连接数据库要用的pymysql模块,并且连接数据库。
host=你本机的ip地址,localhost就是本机的ip地址
user=连接MySQL的用户名
password=连接MySQL的密码
db=操作的数据库名称
cursor为一个对象,如果需要对我们定义的数据库进行操作,直接就对cursor操作即可。
如果想要把爬取下来的数据保存到数据库表中,就必须要先创建表结构,比如在下方最后三行代码中,创建了三张表用于后续保存爬取下来的数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from selenium import webdriver
from time import sleep
import pymysql
# 连接数据库
conn = pymysql.connect(host='localhost',user='root',password='123456',db='db')
cursor = conn.cursor()
#执行一个SQL语句
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))')
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))')
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条.
以下是该案例下爬取数据的代码,可根据实际情况去更改。
# 实现反检测
from selenium.webdriver import ChromeOptions
option = ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
# 实例化一个浏览器对象
bro = webdriver.Chrome(executable_path='./chromedriver',options=option)
# 对贝壳发起请求
bro.get('https://bj.ke.com/')
# 定位搜索按钮,并点击
bro.find_element_by_xpath('//*[@id="beike"]/div[1]/div/div[2]/div/ul/li[2]/a').click()
sleep(2)
for x in range(10):
# 下拉页面
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(5)
# 解析页面
li_list = bro.find_elements_by_xpath('/html/body/div[6]/ul[2]/li')
sleep(1)
for li in li_list:
goods = li.text.split('\n')
# print(goods)
if '新房顾问' in goods[4]:
del goods[4]
for z,y in enumerate(goods):
if y == '关注':
del goods[z]
# print(goods)
a = goods[1].split(' ')
# print(a)
# 获取小区名称
name = a[0]
# 获取售卖情况
sale = a[1]
# 获取房屋类型
house = a[2]
b = goods[2].replace(',','.').split('/')
print(b)
# 获取所在区
big_add = b[0]
# 获取房屋具体位置
small_add = b[2]
if '户型' not in goods[3]:
goods.insert(3,'户型 暂无户型信息 建面 暂无建面信息')
goods[3] = goods[3].replace(' / ','/').replace('/建',' 建')
c = goods[3].split(' ')
# print(c)
# 获取户型
shape = c[1]
# 获取建面
square = c[3]
"""'50000 元/㎡(均价)', '总价1848-2500(万/套)'"""
if '均' not in goods[5]:
goods.insert(5,'暂无均价')
if '总' not in goods[-1]:
goods.append('总价暂无总价')
print(goods)
d = goods[-2].split(' ')
# avg_price = goods[-2][:9]
# print(d)
# 获取均价
avg_price = d[0]
# 获取总价
sum_price = goods[-1][2:].split('(')[0]
e = goods[-3].split(' ')
# print(e)
if '地铁沿线' in e:
e.insert(0, '地铁沿线')
else:
e.insert(0, '无地铁')
if '购物方便' in e:
e.insert(1, '购物方便')
else:
e.insert(1, '无商场')
subway = e[0]
shopping = e[1]
if house == '住宅':
sql = "insert into bk_zz values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
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))
cursor.executemany(sql, param)
elif house == '别墅':
sql = "insert into bk_bs values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
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))
cursor.executemany(sql, param)
else:
sql = "insert into bk_qt values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
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))
cursor.executemany(sql, param)
# 点击翻页
if x == 0:
bro.find_element_by_xpath('/html/body/div[7]/div[2]/a[5]').click()
sleep(3)
elif 1 <= x <= 4:
bro.find_element_by_xpath(f'/html/body/div[7]/div[2]/a[6+{x}]').click()
sleep(3)
else:
bro.find_element_by_xpath(f'/html/body/div[7]/div[2]/a[10]').click()
print(f'第{x+1}页爬取成功')
bro.quit()
# 提交数据,并保存到数据库中
re = cursor.fetchall()
conn.commit()
cursor.close()
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)
需要注意的是,在所有数据插入成功后,要提交数据并且保存到数据库中!!