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记得自己获取
由于也是遍写边改,可能逻辑有点乱,一些地方写得啰嗦重复。也不想改了,这里就分享一下源代码叭。我预处理的东西比较多哦,得看一下,你们才能直接用。

源码链接

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值