selenium自动化爬取信息
在这里只是一个示例,教我自己总结的方法
获取cookie
首先,自动化肯定是要获取cookie用来登录账号的,代码如下:
这里需要自己点几下,登录自己的账号,然后获取cookie信息,保存到文件中,然后后面单独使用
主要知识点
browers = webdriver.Chrome() #打开浏览器
browers.get(url) #访问你的url网站,然后自己登录账号后,会保存到一个文件中
browers.close() #浏览器关闭
list = browers.get_cookies() #获取cookie
with open('../data/cookies.json', 'w', encoding='utf-8') as file: #保存为json文件
json.dump(list, file, indent=2, ensure_ascii=False)
源代码
import json
import time
from selenium import webdriver
browers = webdriver.Chrome() #打开浏览器
url = 'https://bj.meituan.com'
browers.get(url) #访问
time.sleep(30) #30秒内,你自己登录
list = browers.get_cookies() #获取cookie
print(list)
with open('../data/cookies.json', 'w', encoding='utf-8') as file: #保存为json文件
json.dump(list, file, indent=2, ensure_ascii=False)
browers.close() #浏览器关闭
爬取信息
主要知识点
文件操作
xlsx文件系列
book = openpyxl.load_workbook('../景区信息.xlsx') #加载打开已经存在xlsx文件
sheet1 = book['Sheet1'] #选择其Sheet1那一页
len_row = sheet1.max_row #获取其行数
sheet1.cell(num, 8).value #获取单元格对应的值,也可以让其赋值为新值
book.save(filename="../景区信息.xlsx") #修改后记得保存
csv文件系列
with open(path, 'a', encoding='utf-8-sig') as csvfile: #打开csv文件,已追加的形式
file = csv.writer(csvfile) #转化为csv文件的写入
if flag == True:
file.writerow(['评论时间','评分','评论内容']) #写入一行信息
file.writerows([['4','q',21],['5','q',21]]) #直接写入多行
with open('data.csv','w',encoding='utf-8') as csvfile: #字典类型的存储
filedname = ['id','name','age']
file = csv.DictWriter(csvfile,fieldnames=filedname) #字典对象的初始化
file.writeheader() #先输入头信息
file.writerow({'id' : 'Q','name' : 'F','age' : 'Y'}) #添加一行的信息
file.writerow({'id' : '1','name' : 21,'age' : '64'})
with open('data.csv','r',encoding='utf-8') as file: #读出
read = csv.reader(file)
print(read)
for item in read:
print(item)
df = pandas.read_csv('data.csv') #利用pandas来输出这种文件,比较直观
print(df)
xls文件系列
workbook = xlwt.Workbook(encoding='utf-8') #创建
booksheet = workbook.add_sheet('Sheet1', cell_overwrite_ok=True) #创建
booksheet.write(0, 0, '1') # 写入
workbook.save('../data/景区评论/' + location_city + '/' + location_name + '.xls') #保存
html节点获取
这里我是直接用的xpath文法规则来获取的
由于网络的波动,所有有不同的获取方式
这里的节点就是html中信息存储的位置,爬取这些位置的文字信息,然后利用正则提取等方法去规范格式
#直接获取
#xpath中 *代表所有,@class为限定属性,//为所有子孙节点,/为所有直系节点
img_locations = brower.find_elements_by_xpath('//*[@class="common-list-main"]//*[@class="default-list-item clearfix"]/a/img')
#隐式等待获取
#当第一次找不到的时候,会停止查找,一直等你规定的等候时间到了后,再进行查找,如果还是查不到,就会爆出异常。
brower.implicitly_wait(1) #隐式等待,1代表等待的最长时间1秒,根据你自己而定
#显示等待
#在最长等待时间内,他会一直的尝试去查找这个节点。然后查到了,那么就直接进行下一步代码,如果超出最大等候时间,那么抛出错误。
# brower代表你的浏览器,By.XPATH代表你用的什么规则去查找,也可以用css等选择器
click_locations = WebDriverWait(brower, max_wait_time).until(EC.presence_of_all_elements_located(
(By.XPATH, '//*[@class="common-list-main"]//*[@class="default-list-item clearfix"]/a')))
正则提取
idea_tag = '(.*?)|.*?'
idea_evaluation = '(.*?)分(.*?)人.*?' #这是正则表达式
result_tag = re.findall(idea_tag, List[3], re.S) #查找所有符合条件的,并且返回一个列表
#第一个参数代表查找的规则,第二个参数代表查找文本,第三参数re.S表示单行匹配模式 re.M表示多行匹配模式,
result_evaluation = re.findall(idea_evaluation, List[2], re.S)
其他知识
name = '123'
os.mkdir(name) #创建文件夹
os.makedirs(name) #创建文件夹
path = os.path.dirname(os.path.abspath(__file__)) #获取当前的绝对路径
path_1 = os.path.exists() #判断文件是否存在
urlretrieve(img_url, '../data/景区图片/' + location_name + '.jpg') #保存图片
now_url = brower.current_url #获取当前网址
brower.execute_script('window.scrollTo(0,document.body.scrollHeight)') # 页面拉倒最底下
img_url = item.get_attribute('src') #获取其该节点对应属性值,item是你获取的节点
item.click() #点击该节点
item.text #获取节点文字信息
search.send_keys(scenic_name) #往输入框中输入东西
异常处理模块
login
由于网络的不稳定性,以及高频的爬取,爬取过程中会出现各种情况,当出现这种情况后,调用login模块,记录一下,出现问题的景区,然后关闭浏览器一会儿,重新打开再次登录。并且记录下丢失的景区。
def login(location_original_name):
global brower #引用全局的brower
handles = brower.window_handles #获取当前全部浏览器窗口
brower_len = len(handles)
for i in range(0,brower_len): #全部关闭
brower.switch_to.window(brower.window_handles[i]) # 切换
brower.close()
time.sleep(10) #等待有一会儿
brower = webdriver.Chrome() #重新打开浏览器
lost_list.append(location_original_name) #记录出现问题的景区
print(lost_list)
add_cookies() #添加cookies重新登录
except_solve
当出现异常的时候,可能存在多个网页,这个时候你必须得关闭无用的网页,否则,当多次异常后,你的浏览器可能会存在100多个窗口,会把你的电脑内存占爆的
def except_solve():
handles = brower.window_handles #获取所有窗口
brower_len = len(handles)
for i in range(1,brower_len):
brower.switch_to.window(brower.window_handles[i]) # 切换
brower.close() #关闭该窗口
brower.switch_to.window(brower.window_handles[0]) #保留一个窗口,这里看你们随意,不保留就关完然后重新开就是了
保存信息
保存图片
def save_img(img_url, location_name): #img_url表示图片网址
urlretrieve(img_url, '../data/景区图片/' + location_name + '.jpg')
保存景区基本信息
def save_basis_information(map): #这个map字典是你们想要保存的信息,这里我就不提了
# print(map)
for num in range(2, len_row):
location_original_name = sheet1.cell(num, 1).value #这里我原来的文本是有景区名称的,我需要对比,所以下面添了一个对比,对应的存储到我想要的位置上,你们想保存信息,可以直接把if去了,然后自己按自己的需求对应存储
if location_original_name == map['location_original_name']:
sheet1.cell(num, 8).value = map['location_name']
sheet1.cell(num, 9).value = map['location_tag']
sheet1.cell(num, 10).value = map['location_score']
sheet1.cell(num, 11).value = map['location_evaluation_num']
sheet1.cell(num, 12).value = map['location_price']
book.save(filename="../景区信息.xlsx") #修改后保存
保存景区评论
def save_comment_information(map,flag,num,booksheet): #map是保存信息,num是第几条评论,booksheet是工作铺文件
if flag == True: #因为他是一页一页的点,然后获取评论,所以我判断他有没有标题栏
booksheet.write(0, 0, '评论时间')
booksheet.write(0, 1, '评价分数')
booksheet.write(0, 2, '评论详细')
booksheet.write(num, 0, map['comment_date'])
booksheet.write(num, 1, map['comment_star'])
booksheet.write(num, 2, map['comment_detail'])
依次爬取景点及获取信息html节点
依次获取景点
我的景区文件中是获取了原始景区名称的,所以我直接拿出来然后搜索就是了。你们要是想一个一个爬,就搜索北京景区这种。然后一页一页爬,方法都差不多。
def get_location():
location_now = 0 #现在爬取景区的位置
for num in range(2, len_row+1): #这里打开的是我的原始景区名单
location_original_name = sheet1.cell(num, 1).value #获取景区
location_city = sheet1.cell(num,2).value #获取景区城市,这些都是我预处理好的
location_now += 1
if location_now <= now_sum: #这里是我进行异常处理用的,用于处理网络异常,然后不想爬取前面的
continue
brower.get(url + 's/' + location_original_name + '/') #打开该网站
time.sleep(1)
now_url = brower.current_url #获取当前网址
print(now_url)
if (len(now_url) >= 61 and now_url[:61] == login_url) or now_url == lost_url: #异常
login(location_original_name) #重新登录一下
time.sleep(3)
try:
get_basis_information(location_original_name,location_city) #下面的一个模块
except Exception as e: #异常获取
print(e)
print('失败')
lost_list.append(location_original_name) #异常处理的城市
except_solve() #异常处理模块
time.sleep(5)
获取景区基本信息
def get_basis_information(location_name,location_city):
basis_locations = WebDriverWait(brower, max_wait_time).until(
EC.presence_of_all_elements_located((By.XPATH, '//*[@class="common-list-main"]'))) #显示等待查找这个景点的基本信息,因为你搜索的景点如果没有,那么他就查找不到,那么就抛出异常了
print('one')
img_locations = brower.find_elements_by_xpath('//*[@class="common-list-main"]//*[@class="default-list-item clearfix"]/a/img') #获取图片
print('two')
click_locations = brower.find_elements_by_xpath('//*[@class="common-list-main"]//*[@class="default-list-item clearfix"]/a') #获取点击节点
print('three')
# print(locations)
img_save_name = ''
for item in basis_locations:
#这里用for的原因是我用的是find_elements_by_xpath,返回结果是一个列表,如果用find_element_by_xpath,如果找不到就会报错,所有这样遍历一下,只获取第一个景点
List = item.text.split()
# print(List)
if List[0] == '对不起,没有符合条件的商家': #没有该景区
lost_list.append(location_name)
print(lost_list)
break
idea_tag = '(.*?)|.*?'
idea_evaluation = '(.*?)分(.*?)人.*?' #这里我是正则提取了一下,这是正则表达式
result_tag = re.findall(idea_tag, List[3], re.S)
result_evaluation = re.findall(idea_evaluation, List[2], re.S) #查找
name_tag = ''
img_save_name = List[1] #图片保存的文件名
for i in result_tag: #这里是因为我正则好像错了,我也没改,直接这样把景区的名字获取了
if i != '|':
name_tag += i
else:
break
map = { #你要传的参,保存着你需要保存的信息
'location_original_name': location_name,
'location_name': List[1],
'location_score': result_evaluation[0][0] + '分',
'location_evaluation_num': result_evaluation[0][1],
# 'location_tag': result_tag[0],
'location_tag': name_tag,
'location_price': List[5]
}
save_basis_information(map) #保存基本信息模块
break
for item in img_locations: #同理
img_url = item.get_attribute('src') #获取其该节点对应属性值
# print(item.get_attribute('src'))
save_img(img_url, img_save_name) #保存图片
break
for item in click_locations:
item.click() #点击发生跳转
get_comments_information(location_name,location_city) #这是获取评论信息的模块
break
time.sleep(1)
获取景区评论
def get_comments_information(location_name,location_city):
brower.switch_to.window(brower.window_handles[1]) # 切换窗口,因为点击发生了跳转
page_num = 0 #当前爬取评论的页数
comment_sum = 0 #当前一共爬取了多少条评论
csv_name = True #
flag = True #是否继续爬取的标志
workbook = xlwt.Workbook(encoding='utf-8')
booksheet = workbook.add_sheet('Sheet1', cell_overwrite_ok=True) #爬取一共景点就创建一个对应的xls文件,用来存储评论信息
try:
while flag:
flag = False
page_num += 1
if page_num > 30: #页数
break
#获取评论信息节点
comments = WebDriverWait(brower, max_wait_time).until(
EC.presence_of_all_elements_located((By.XPATH, '//*[@class="comment-main"]')))
print('four')
#获取对应评论的评价分数
star = WebDriverWait(brower, max_wait_time).until(
EC.presence_of_all_elements_located((By.XPATH, '//*[@class="comment-main"]//*[@class="rate-stars-ul rate-stars-light"]')))
print('five')
#下一页评论按钮
next_button = WebDriverWait(brower, max_wait_time).until(
EC.presence_of_all_elements_located(
(By.XPATH, '//*[@class="pagination-item pagination-item-comment next-btn active"]')))
print('six')
#有一些是有点击查看全文的,需要手动点击一下才能获取评论全文
read_button = brower.find_elements_by_xpath('//*[@class="read-btn"]')
print('seven')
for item in read_button: #获取后,都点一下
item.click()
detail_comments = brower.find_elements_by_xpath('//*[@class="user-comment"]') #评论具体内容
detail_comments_date = brower.find_elements_by_xpath('//*[@class="comment-date"]') #评论日期
detail_comments_list = []
detail_comments_date_list = []
star_list = []
# print(detail_comments)
for item in detail_comments: #保存每一条评论
comment = item.text
detail_comments_list.append(comment)
for item in detail_comments_date: #保存每一条评论的日期
date = item.text
detail_comments_date_list.append(date)
for item in star: #保存每一条评论的评价分数
star_num = item.get_attribute('style')
#因为这里他是一个图,是一个百分比,得自己获取后计算一下
flag1 = False
star_num_1 = ''
for i in star_num:
if i == '%':
break
if flag1 == True:
star_num_1 += i
if i == ' ':
flag1 = True
num = (int(star_num_1)) / 100 * 5
star_list.append(num)
for i in range(len(detail_comments)): #保存每一条评论
comment_sum += 1
map = {
'comment_detail' : detail_comments_list[i],
'comment_date' : detail_comments_date_list[i],
'comment_star' : star_list[i]
}
#调用相应模块
save_comment_information('../data/景区评论/' + location_name + '.xls', map, csv_name, comment_sum,workbook,booksheet)
csv_name = False #这里的意思是,标题栏只保存一次
for item in next_button: #点击下一页评论
item.click()
flag = True
time.sleep(1)
except Exception as e: #异常
print(e)
finally: #最后都要保存一下文件
workbook.save('../data/景区评论/' + location_city + '/' + location_name + '.xls')
time.sleep(1)
brower.close() #爬取完毕后,关闭对应网页
brower.switch_to.window(brower.window_handles[0]) # 切换回去1
本次爬取所用的源代码
上面的cookie记得自己获取
由于也是遍写边改,可能逻辑有点乱,一些地方写得啰嗦重复。也不想改了,这里就分享一下源代码叭。我预处理的东西比较多哦,得看一下,你们才能直接用。