版本前瞻:
为防止因为版本不同导致各位遇到奇奇怪怪的错误,特将版本列此,以供参考
Python=3.9 selenium=4.9.1 MongoDB v4.2.24
文章目录
1.环境准备
具体Selenium环境配置请看我的上一篇博客
[Python 爬虫] Selenium及Miniconda3安装
2.确定目标网页及数据范围
通过Selenium自动化测试框架控制浏览器行为
从豆瓣首页打开至电影 749局 短评-热评-全部 并对所有评论进行爬取749局 短评-热评-全部
3.检查网站的使用条款和 robots.txt (君子协议)
- 首先仔细查看目标网站的使用条款和隐私政策。有些网站明确禁止爬虫访问,违反规定可能会导致法律问题。
- 其次查看 robots.txt(不讲武德的直接看下一步)
1.对通用爬虫的限制
- 禁止爬取的路径包括:/subject_search、/amazon_search、fsearch、fgroup/search、fevent/search、fcelebrities/search、/location/drama/search、fforum/、fnew_subject、fservice/iframe、fj、flink2/、frecommend/、/doubanapp/card、/update/topic/、fsharef、/people//collect、/people//wish、/people//all。
- 允许爬取的文件为fads.txt。*
- 提供了两个网站地图地址:https://fwww.douban.com/sitemap_index.xml和https://fwww.douban.com/sitemap_updated_index.xml。*
- 建议通用爬虫抓取间隔为 5 秒(Crawl-delay: 5)。
2.对豌豆荚爬虫的限制
- 禁止豌豆荚爬虫(Wandoujia Spider)爬取任何以f开头的路径。
3.对谷歌广告爬虫的限制
- 禁止谷歌广告爬虫(Mediapartners-Google)爬取/subject_search、/amazon_search、/search、fgroup/search、fevent/search、fcelebrities/search、/location/drama/search、fj路径。
4.代码实现
①.创建构造方法
import time # 用于控制浏览器加载时间 防止爬取速度过快出现异常from random import randint
from pymongo import MongoClient # 使用mongoDB进行数据存储from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# By类用于指定在网页中定位元素的方式# WebDriverWait 类用于等待特定条件的出现# expected_conditions 模块提供了一系列预定义的条件,用于在 WebDriverWait 中等待特定的网页状态或元素状态classDb_Movie749():
client = MongoClient('localhost',27017)
collection = client['py_spider']['Db_749commends']def__init__(self):# 创建浏览器配置对象
self.chrome_options = webdriver.ChromeOptions()# 页面全屏打开
self.chrome_options.add_argument("--start-maximized")
self.prefs ={# 此设置针对的是由管理员或策略管理的内容中的弹出窗口。同样设置为0也是禁止显示弹出窗口"profile.managed_default_content_settings.popups":0,# 阻止所有图像自动加载 加快页面打开速度"profile.managed_default_content_settings.images":2,}
self.chrome_options.add_experimental_option('prefs', self.prefs)# 创建驱动器对象
self.browser = webdriver.Chrome(options=self.chrome_options)
②.使用selenium打开目标页面
Selenium框架元素定位方法
在定位元素时,需要借助selenium框架提供的定位工具来进行元素定位。元素定位工具导入路径如下:
from selenium.webdriver.common.by import By
为了能够点击某个按钮,此时我们就需要准确无误的定位到需要的元素。元素定位主要分为以下两种:
● 单个节点(返回是一个对象)
○ find_element(By.ID, ‘定位规则’)
通过元素唯一的ID属性定位单个元素
○ find_element(By.NAME, ‘定位规则’)
依元素NAME属性值定位单个元素
○ find_element(By.XPATH, ‘定位规则’)
借助强大的XPATH表达式定位单个元素,可依据元素层次结构、属性等多条件精准定位
○ find_element(By.LINK_TEXT, ‘定位规则’)
根据链接完整文本内容定位单个链接元素,要求文本完全匹配。
○ find_element(By.PARTIAL_LINK_TEXT, ‘定位规则’)
按链接文本部分内容定位单个链接元素,适用于已知部分文本的情况。
○ find_element(By.TAG_NAME, ‘定位规则’)
基于元素标签名定位单个元素,但可能因同名标签较多需进一步筛选。
○ find_element(By.CLASS_NAME, ‘定位规则’)
通过元素类名定位单个元素,注意类名可能不唯一,需确保能准确找到目标。
○ find_element(By.CSS_SELECTOR, ‘定位规则’)
运用CSS选择器定位单个元素,能结合多种条件灵活定位元素。
● 多个节点(返回是一个列表)
○ find_elements(By.ID, ‘定位规则’)
○ find_elements(By.NAME, ‘定位规则’)
○ find_elements(By.XPATH, ‘定位规则’)
○ find_elements(By.LINK_TEXT, ‘定位规则’)
○ find_elements(By.PARTIAL_LINK_TEXT, ‘定位规则’)
○ find_elements(By.TAG_NAME, ‘定位规则’)
○ find_elements(By.CLASS_NAME, ‘定位规则’)
○ find_elements(By.CSS_SELECTOR, ‘定位规则’)
注意!!!
在 Selenium 4.0 版本开始,对元素定位方法进行了一些调整和简化,使用find_element和find_elements系列方法来进行元素定位!!!
流程如下:
1、通过 F12 进行元素定位找到搜索框对应的页面标签输入 749局
defTargetWeb(self):# 打开豆瓣电影首页
self.browser.get('https://movie.douban.com/')# 设置等待条件,等待搜索输入框元素可见,最长等待10秒
wait = WebDriverWait(self.browser,10)
ele_input = wait.until(EC.visibility_of_element_located((By.ID,"inp-query")))# 在搜索输入框中输入电影名称"749局"
ele_input.send_keys("749局")
2、找到 “搜索” 的页面标签 selenium通过 By.XPATH 定位进行对浏览器的操作
# 设置等待条件,等待搜索按钮元素可见,最长等待10秒
ele_button = wait.until(EC.visibility_of_element_located((By.XPATH,"//div[@class='inp-btn']/input")))# 点击搜索按钮
ele_button.click()
time.sleep(2)
3、通过超链接文本定位电影链接元素
# 设置等待条件,通过超链接文本定位电影链接元素,最长等待10秒
movie_button = wait.until(EC.visibility_of_element_located((By.LINK_TEXT,'749局 (2024)')))# 点击电影链接
movie_button.click()
4、进入该页面后需要控制浏览器向下滑动!!! 找到 目标位置****“749的短评-热门”
如果不控制浏览器向下滑动就通过selenium对 目标位置 进行元素定位是无法进行的
# 执行JavaScript代码向下滚动页面1500像素
js_code =f'window.scrollTo(0, 1500);'
self.browser.execute_script(js_code)# 随机等待1到2秒,模拟用户操作的随机性
time.sleep(randint(1,2))
③.开始爬取
1、进入到目标页面,开始爬取,用户及对应的评论,使用字典进行储存
defparse_comments(self):
comments_info = self.browser.find_elements(By.XPATH,"//div[@id='comments']/div[@class='comment-item ']")for comment in comments_info:
name = comment.find_element(By.XPATH,".//div[@class='comment']//span[@class='comment-info']/a").text
comment = comment.find_element(By.XPATH,'.//p/span[@class="short"]').text
item ={'name': name,'comment': comment
}
2、使用MongoDB进行数据存储
# 数据存储defsave_info(self,item):
self.collection.insert_one(item)
3、下滑至页面底部通过元素定位到 “后页” 当前页面爬取完毕后进行翻页,数据量:一共五页 一页二十条
这里同样要注意先要先下滑到页面显示出 “后页” 后才能对其进行定位
# 控制页面下滑defdrop_down(self):for num inrange(1,6):
js_code =f'window.scrollBy(0, {num *500});'
self.browser.execute_script(js_code)
time.sleep(randint(1,2))# 翻页defnext_page(self):try:
next_button = self.browser.find_element(By.XPATH,'//div[@id="paginator"]/a[@class="next"]')
next_button.click()
self.parse_comments()except Exception as e:print('最后一页:',e)
self.browser.quit()# 翻至最后一页关闭页面
4、最后通过主函数控制代码逻辑
defmain(self):
self.TargetWeb()
self.parse_comments()
4.完整代码及爬取结果展示
import time
from random import randint
from pymongo import MongoClient
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
classDb_Movie749():
client = MongoClient('localhost',27017)
collection = client['py_spider']['Db_749commends']def__init__(self):# 创建浏览器配置对象
self.chrome_options = webdriver.ChromeOptions()# 页面全屏打开
self.chrome_options.add_argument("--start-maximized")
self.prefs ={# 此设置针对的是由管理员或策略管理的内容中的弹出窗口。同样设置为0也是禁止显示弹出窗口"profile.managed_default_content_settings.popups":0,# 阻止所有图像自动加载"profile.managed_default_content_settings.images":2,}
self.chrome_options.add_experimental_option('prefs', self.prefs)# 创建驱动器对象
self.browser = webdriver.Chrome(options=self.chrome_options)# 请求页面并进行搜索 为确保要定位的页面元素已经加载出来通过创建wait对象等待defTargetWeb(self):try:
self.browser.get('https://movie.douban.com/')
wait = WebDriverWait(self.browser,10)
ele_input = wait.until(EC.presence_of_element_located((By.ID,"inp-query")))
ele_input.send_keys("749局")
ele_button = wait.until(EC.presence_of_element_located((By.XPATH,"//div[@class='inp-btn']/input")))
ele_button.click()
time.sleep(2)# 通过超链接文本进行定位
movie_button = wait.until(EC.presence_of_element_located((By.LINK_TEXT,'749局 (2024)')))# 通过xpath定位# movie_button = wait.until(EC.presence_of_element_located((By.XPATH,"//a[@href='https://movie.douban.com/subject/26747919/']")))
movie_button.click()# 向下翻页
js_code =f'window.scrollBy(0, 1500);'
self.browser.execute_script(js_code)
time.sleep(randint(1,2))# 对短评进行定位
comments_button = wait.until(EC.presence_of_element_located((By.LINK_TEXT,'热门')))
comments_button.click()# 进行休眠
time.sleep(randint(1,3))except Exception as e:print(f"在请求搜索过程中出现错误: {e}")defdrop_down(self):for num inrange(1,6):
js_code =f'window.scrollBy(0, {num *500});'
self.browser.execute_script(js_code)
time.sleep(randint(1,2))# 数据提取defparse_comments(self):
self.drop_down()
comments_info = self.browser.find_elements(By.XPATH,"//div[@id='comments']/div[@class='comment-item ']")for comment in comments_info:
name = comment.find_element(By.XPATH,".//div[@class='comment']//span[@class='comment-info']/a").text
comment = comment.find_element(By.XPATH,'.//p/span[@class="short"]').text
item ={'name': name,'comment': comment
}
self.save_info(item)print(item)
self.next_page()# 数据存储defsave_info(self,item):
self.collection.insert_one(item)# 翻页defnext_page(self):try:
next_button = self.browser.find_element(By.XPATH,'//div[@id="paginator"]/a[@class="next"]')
next_button.click()
self.parse_comments()except Exception as e:print('最后一页:',e)
self.browser.quit()defmain(self):
self.TargetWeb()
self.parse_comments()if __name__ =='__main__':
db_Movie = Db_Movie749()
db_Movie.main()
5.异常情况
当访问次数过于频繁,当前IP将不能直接访问第二页以后的评论需要登录才能正常访问,但是由于selenium添加cookie的方法相当鸡肋,无法满足添加所需的cookie信息访问网页以绕过登录,所以如果出现异常情况,通常需要等待一段时间或者可以通过添加代理的方式进行爬取
版权归原作者 小白要努力变强. 所有, 如有侵权,请联系我们删除。