你将看到
- selenium自动化抓取
- 携程抓取遇到的问题
- 可借鉴该思路爬取其他网站
1.分析网页
最近导师给了任务,让爬取携程的邮轮的用户评论数据,对于一个非编程出生的门外汉来说这个任务并不简单,起早贪黑,好在不懂的可以看编程前辈们的博客。
携程网页特点
示例网址:https://cruise.ctrip.com/c/8372.html#departure=2019-07-29&sellerid=39348_5049
- 抓取评论时,评论翻页为ajax异步加载,尝试用动态加载的方法来抓取,F12打开审查元素的Network,采用移动端来抓取,勾选preserve log刷新,发现xhr下的json文件有所需的信息
- 尝试用构建url列表,用requests获取包含评论的json文件,再解析一下不就能将信息提取了吗?
- 但问题来了,分析url规律时,发现所有每次请求的包含所需信息的不同json文件的url竟都是相同的,都为https://sec-m.ctrip.com/restapi/soa2/12431/GetCommentList?_fxpcqlniredt=09031051210259264792&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10320606450&__gw_platform=H5
并且打开url报错,请求不到信息,json文件如下
ResponseStatus
Timestamp "/Date(1557366295878+0800)/"
Ack "Failure"
Errors
0
Message "PARAM_ERROR, 请求字符串错误,condition不能为空"
ErrorCode "1002"
ErrorFields []
Extension
0
Id "CruiseTraceId"
Value "4a6a4ef2287b46daae809c53ce6f0253"
1
Id "CLOGGING_TRACE_ID"
Value "5629678003315929336"
2
Id "RootMessageId"
Value "921812-0a1c7300-432601-1467766"
- 一筹莫展时咨询大神查阅了一些博客,换一种思路,用selenium来抓取。前辈文章:https://blog.csdn.net/qq_33879934/article/details/82315389
2.代码实现
selenium的环境配置
Firefox和Chrome相关版本有很多博客介绍,我用的是Firefox,配置好geckodriver,就不用进行其他的配置就能实现添加cookie、代理IP和User-Agent的功能。(网上很多博客都要求安装一些插件才能实现上述功能,亲自踩坑,并不需要安装也能进行添加cookie、代理IP和User-Agent)
selenium可通过
- 添加Cookie(直接添加用户名密码模拟人为登陆较为方便)
- 添加代理IP
- 添加User-Agent
来爬取反爬严重的网页
由于本实例数据量小,只添加一个账号,若有需要可收集cookie、代理IP和User-Agent列表,遍历到相应函数里就行
结果示例
index序号代码有点问题,不是从1开始,但是影响不大,稍作修改就行。
代码
# -*- coding: UTF-8 -*-
import csv
import re
import time
from selenium import webdriver
import random
# ============================================================================
#******* 更换相应邮轮页面的url和评论页数pages即可,爬 *******
#******* 完一条邮轮更换携程账号名ID和密码和密码pwd *******
#=============================================================================
url = 'https://cruise.ctrip.com/c/8372.html#departure=2019-07-29&sellerid=39348_5049'
ID = '你的携程账号'
pwd = '你的携程密码'
browser = webdriver.Firefox()
browser.get(url)
time.sleep(1)
# 登陆
browser.find_element_by_xpath('/html/body/div[1]/div/ul[2]/li[1]/a/span').click()
browser.find_element_by_id('nloginname').send_keys(ID)
time.sleep(0.7)
browser.find_element_by_id('npwd').send_keys(pwd)
time.sleep(0.8)
button_click = browser.find_element_by_id('nsubmit').click()
time.sleep(5)
# 获取评论总页数
first_page_html = browser.page_source
total_pages = re.findall('cyl_page_point.*?data-index="772">(.*?)</a><a', first_page_html, re.S) # 获取页码总数
pages = int(total_pages[0]) # 字符串转化为整数
for i in range(pages): # 遍历页数,
print('正在爬取第{}页数据...'.format(i+1))
html = browser.page_source
with open(r'D:\携程\第{}页源代码.html'.format(i+1), 'w', encoding='utf-8') as f: # 将获取到的每页源代码保存,以后可能会用到
f.write(html)
# 使用正则表达式提取数据
pattern_total = re.compile('<div class="reviews_item_box">.*?<div class="comment_dtl commentDetailContainer">.'
'*?<div class="subDetailContainer"(data-title=".*?">)?(.*?)</div>', re.S)
pattern_each = re.compile('<h2>(.*?)</h2>.*?<p class="tour">(.*?)</p>.*?</div>', re.S)
items_total = re.findall(pattern_total, html) # 获取总评
items_each = re.findall(pattern_each, html) # 获取岸上活动,领队服务评价
with open('总评.csv', 'a', newline='', encoding='utf-8') as csvfile: # 创建csv文件写入总评
writer_total = csv.writer(csvfile)
# writer_total.writerows([['index', 'comments']])
for item in items_total: # 保存总评
# print(item)
msg = item[1].strip()
writer_total.writerow([msg]) # 写入csv文件
with open('分评.csv', 'a', newline='', encoding='utf-8') as f: # 写入分评
writer_each = csv.writer(f)
# writer_each.writerows([['评价项目', '内容']])
for each in items_each:
title_ = each[0].strip()
content = each[1].strip()
writer_each.writerows([[title_, content]])
button = browser.find_element_by_class_name('cyl_page_next') # 获取‘下一页’按钮
button.click()
sec = random.randint(4, 6)
time.sleep(sec) # 间隔sec秒打开下一个网页