在网络爬虫中,使用Scrapy和Selenium相结合是获取动态网页数据的有效方式。本文将介绍如何使用Scrapy和Selenium构建一个爬取携程旅游信息的爬虫,实现自动化获取数据的过程。
本文已对部分关键URL进行处理,本文内容仅供参考,请勿用以任何商业、违法行径
简介
携程(you.ctrip.com)是一个提供旅游信息的网站,但它的部分内容可能是动态加载的,难以直接通过Scrapy获取。这时就需要借助Selenium这样的工具,模拟浏览器行为进行数据的获取和处理。
工具准备
- Scrapy: 一个用于爬取网站并提取结构化数据的强大框架。
- Selenium: 一个自动化测试工具,可以模拟用户操作浏览器的行为。
- ChromeDriver: 作为Selenium WebDriver的一部分,用于驱动Chrome浏览器进行自动化测试。 具体下载地址和环境配置可参考: 使用Selenium和bs4进行Web数据爬取和自动化(爬取掘金首页文章列表) - 掘金 (juejin.cn)
实现步骤
- 设置Scrapy项目: 创建Scrapy项目并配置爬虫。
- 编写爬虫: 使用Scrapy的Spider编写爬虫,设置起始URL和数据提取规则。
- 设置Selenium中间件: 创建Selenium中间件,用于处理需要动态加载的页面内容。
- 利用Selenium模拟浏览器行为: 在Selenium中间件中,使用ChromeDriver启动浏览器,模拟点击、等待页面加载等操作。
- 处理页面内容: 利用Selenium获取到的页面内容,提取需要的信息并返回给Spider。
- 数据存储或处理: Spider获取到数据后,可以选择存储到数据库或进行其他处理。
代码实现
爬虫部分
- 爬虫启动:- 爬虫启动后,读取Excel文件中的景区名称作为搜索关键词。- 构建对应的携程搜索链接,并发起Request请求。
defstart_requests(self):
df = pd.read_excel("D:\code\Scrapy\scrapy_tour\A级景区(按省份).xlsx")
scenic_namelist = df['景区名称']
dflen =len(scenic_namelist)for i inrange(10641, dflen):
key = scenic_namelist[i]
newurl =''+ key
yield Request(url=newurl, meta={'use_selenium':True,'title': key,'id': i,'closeid': dflen -1})
- Selenium配置: - 通过Selenium进行浏览器模拟,创建Chrome实例,设置headless模式(无界面运行)。- 使用预设的Chrome浏览器驱动(chromedriver.exe),打开携程首页,读取并加载已保存的Cookie信息,实现自动登录。
defcreat_browser(self):# ... ChromeOptions设置及浏览器实例化 ...
browser = webdriver.Chrome(service=service, options=options)
browser.get("")
browser.delete_all_cookies()withopen('scrapy_tour/cookies_xiecheng.json','r', encoding='utf-8')as f:
listCookies = json.loads(f.read())for cookie in listCookies:
browser.add_cookie(cookie)
browser.refresh()return browser
- 评论信息采集: - 在页面加载完毕后,使用Selenium定位和等待元素加载,获取评论相关内容(评分、评论内容、评论时间等)。- 实现翻页操作,模拟用户点击下一页,持续获取更多评论信息,直至达到设定的页数或无法继续翻页。
defparse(self, response):# ...whileTrue:# 定位评论元素,等待加载
elements = WebDriverWait(self.driver,3).until(lambda x: x.find_elements(by=By.CSS_SELECTOR, value='.commentList .commentItem .contentInfo'))# 获取评论相关信息# 翻页操作# ...
- 数据存储: - 将获取的评论信息存储到
XiechengItem
中,并利用Scrapy框架的Item Pipeline进行后续处理和存储。
ifidisnotNoneand title isnotNoneand commentstr!='':
xiecheng_item['Title']= title
xiecheng_item['Commentlist']= commentstr
xiecheng_item['AverageScore']= averagescore
xiecheng_item['OpenTime']= time
xiecheng_item['Number']= number
xiecheng_item['Id']=idyield xiecheng_item
通过这样的爬取方式,可以获取携程上景区的评论信息,包括评分、评论内容、评论时间等,为进一步分析景区口碑提供了数据支持。
中间件
classxiecheng_SeleniumMiddleware:def__init__(self):
self.driver = creat_browser()
self.winflag =0# 释放资源defclosemidd(self,request):if request.meta.get('closeid')==request.meta.get('id'):
self.driver.quit()defprocess_request(self, request, spider):if request.meta.get('use_selenium'):
self.driver.get(request.url)# 在这里使用Selenium进行页面交互,如点击按钮、填写表单等# 并等待页面加载完成# 获取页面内容# page_source = self.driver.page_source# 转换为字节格式,以避免一些编码错误# self.driver.implicitly_wait(5) # 设置隐式等待时间为5秒try:# 显示等待确保能找到元素,显示等待3s# raise IgnoreRequest("强制取消")
elements = WebDriverWait(self.driver,3).until(lambda x: x.find_elements(by=By.CSS_SELECTOR, value='.guide-main-item-bottom .title'))
Similarity_score =[]for element in elements:
title = element.text
oldtitle = request.url.split('=')[1]# url 转码中文
oldtitle = urllib.parse.unquote(oldtitle)
Similarity_score.append(get_similarity(oldtitle, title))# if Similarity_score[-1][4] >=50:# print(Similarity_score[-1])
max_score =None
max_index =Noneif Similarity_score!=[]:for index, score inenumerate(Similarity_score):if max_score ==Noneor max_score[-1]< score[-1]:
max_score = score
max_index = index
# 找到最匹配的选项# print('max', max_score)# print(max_index)# 若成功找到最匹配项,且各种匹配方式得分都大于50.点击该景点获取urlif max_score !=Noneand max_score[2]>=50and max_score[3]>=50and max_score[4]>=50:print('max', max_score)
elements[max_index].click()print("click yes")# self.winflag+=1# thiswim=self.winflag
li = self.driver.window_handles # 出现多个窗口,需要切换句柄,先获取句柄列表iflen(li)>=2:
self.driver.switch_to.window(li[-1])# 切换句柄# 显示等待热度数据,等待详情页显示完毕
hot = WebDriverWait(self.driver,3).until(lambda x: x.find_elements(by=By.CSS_SELECTOR, value='.heatView .heatScoreView .heatScoreText'))# 将详情页信息发送到spider
body = to_bytes(self.driver.page_source, encoding='utf-8')print('传入爬虫url')print(self.driver.current_url)# 修改中间件判断参数
request.meta['use_selenium']=False
response = HtmlResponse(url=self.driver.current_url, body=body, encoding='utf-8',
request=request)# 关闭窗口句柄减一
self.driver.close()# 切换至搜索页面窗口iflen(li)>=1:
self.driver.switch_to.window(li[0])# self.winflag-=1
self.closemidd(request)return response
else:
self.closemidd(request)raise IgnoreRequest("未找到相似度合格的元素")except Exception as e:raise IgnoreRequest("中间件报错,或可能是显示等待的元素等待超时或是元素不存在。")
spider.logger.error(f"Error: 中间件报错,{e}")# return Noneelse:print('未进入携程的中间件,被转移')# 不使用 Selenium,直接返回 None,让 Scrapy 使用默认的下载器处理这个请求# passreturnNone
以上是一个用于Scrapy爬虫的中间件,主要功能是通过Selenium模拟浏览器操作,实现页面交互和内容获取。
- 初始化:- 在初始化方法中,创建了一个浏览器实例
self.driver
。- 设定了一个标志位self.winflag
用于跟踪窗口数量。 - 请求处理:-
process_request
方法处理请求,当请求中包含指定的参数use_selenium
时,使用Selenium处理请求。- 使用WebDriverWait
进行页面元素的显示等待,等待指定元素加载完成。- 根据元素内容的相似度进行匹配,点击最匹配的选项,获取相关详情信息。- 如果成功找到匹配项且相似度符合要求,切换到详情页,等待详情页数据加载完毕,获取页面信息并构造HtmlResponse
对象。- 关闭详情页窗口,返回HtmlResponse
对象,传递给爬虫处理。- 若未找到相似度合格的元素或发生异常,则忽略该请求,不进行处理。 - 资源释放:-
closemidd
方法用于释放资源,在请求处理完成后,根据条件判断是否关闭浏览器窗口句柄。
Pipeline管道
在Scrapy框架中,处理数据的管道(Pipeline)起着至关重要的作用。其中,MySQLPipeline是一种常见的数据处理管道,用于将爬取的数据存储到MySQL数据库中。
classMySQLPipeline:def__init__(self, mysql_host, mysql_port, mysql_database, mysql_user, mysql_password):# 初始化连接参数和数据库连接实例# ...@classmethoddeffrom_crawler(cls, crawler):# 从爬虫配置中获取数据库连接参数# ...defopen_connection(self):# 手动开启数据库连接# ...defopen_spider(self, spider):# 在爬虫启动时打开数据库连接# ...defclose_spider(self, spider):# 在爬虫关闭时关闭数据库连接并提交数据# ...defprocess_item(self, item, spider):# 处理爬取到的数据,并根据数据类型执行相应的数据库插入操作# ...defwrite_data(self, sql):# 执行批量数据写入操作# ...
- 初始化:MySQLPipeline类在初始化时接收MySQL数据库连接所需的参数,并创建了数据库连接的实例以及一个用于暂存数据的列表。
- 从配置中获取参数:通过
from_crawler
方法从Scrapy的配置中获取MySQL数据库连接的参数。 - 数据库连接管理:
open_connection
方法用于手动开启数据库连接;open_spider
方法在爬虫启动时调用,也用于开启数据库连接;close_spider
方法在爬虫关闭时调用,用于关闭数据库连接并提交数据到数据库。 - 数据处理:
process_item
方法根据不同的数据类型,执行相应的数据库插入操作,将数据存储到对应的数据表中。 - 批量写入数据:
write_data
方法用于执行批量数据写入操作,将暂存的数据列表批量写入数据库表中,并在操作完成后清空数据列表。
这样我们就成功的构建了一个旅游信息采集爬虫。
注意事项
- 页面结构变化: 网站的页面结构可能会不定期更改,导致原有的提取规则失效,需要定期检查和更新提取规则。
- 反爬措施: 网站可能有反爬措施,需要注意不要频繁请求或暴露爬虫行为。
总结
通过Scrapy和Selenium的结合,我们可以构建一个能够有效获取旅游信息的爬虫。但是需要注意,爬虫在实际应用中需要遵守网站的规则,避免对网站造成过大压力或触发反爬机制。
以上就是利用Scrapy和Selenium构建旅游信息爬虫的基本流程和实现方法。
(注意:以上代码和步骤仅为示例,实际爬虫需根据网站的页面结构和变化进行相应调整和处理。)
版权归原作者 冷月半明 所有, 如有侵权,请联系我们删除。