51Testing软件测试论坛

标题: Python + Selenium 爬取网易云课堂课时标题及时长 [打印本页]

作者: lsekfe    时间: 2021-9-24 09:44
标题: Python + Selenium 爬取网易云课堂课时标题及时长
 目标页面
  study.163.com/course/intr…
  一开始用常规方法请求下来,发现源码中根本找不到任何课时信息,说明该网页用 JavaScript 来动态加载内容。
  使用开发者工具分析一下,发现浏览器请求了如下的地址获取课时详情信息:
  study.163.com/dwr/call/pl…
  在预览界面可以看到各课时信息的 Unicode 编码。
[attach]134562[/attach]
尝试直接请求上述地址,显然会报错,不想去研究请求头具体应该传哪些参数了,直接上 Selenium,反正就爬一个页面,对性能没什么要求。
  代码
  说明
  ·study163seleniumff.py 是主运行文件
  · helper.py 是辅助模块,与主运行文件同目录
  · geckodriver.exe 需要放在 ../drivers/ 这个相对路径下
  study163seleniumff.py

  1. from selenium.webdriver import Firefox
  2.   from selenium.webdriver.firefox.options import Options
  3.   from lxml import etree
  4.   import csv
  5.   from helper import Chapter, Lesson
  6.   # 请求数据
  7.   url = 'https://study.163.com/course/introduction.htm?courseId=1006078212#/courseDetail?tab=1'
  8.   options = Options()
  9.   options.add_argument('-headless')  # 无头参数
  10.   driver = Firefox(
  11.       executable_path='../drivers/geckodriver',
  12.       firefox_options=options)
  13.   driver.get(url)
  14.   text = driver.page_source
  15.   driver.quit()
  16.   # 解析数据
  17.   html = etree.HTML(text)
  18.   chapters = html.xpath('//div[@class="chapter"]')
  19.   TABLEHEAD = ['章节号', '章节名', '课时号', '课时名', '课时长']
  20.   rows = []
  21.   for each in chapters:
  22.       chapter = Chapter(each)
  23.       lessons = chapter.get_lessons()
  24.       for each in lessons:
  25.           lesson = Lesson(each)
  26.           chapter_info = chapter.chapter_info
  27.           lesson_info = lesson.lesson_info
  28.           values = (*chapter_info, *lesson_info)
  29.           row = dict(zip(TABLEHEAD, values))
  30.           rows.append(row)
  31.   # 存储数据
  32.   with open('courseinfo.csv', 'w', encoding='utf-8-sig', newline='') as f:
  33.       writer = csv.DictWriter(f, TABLEHEAD)
  34.       writer.writeheader()
  35.       writer.writerows(rows)
复制代码
helper.py
  1. class Chapter:
  2.       def __init__(self, chapter):
  3.           self.chapter = chapter
  4.           self._chapter_info = None
  5.       def parse_all(self):
  6.           # 章节号
  7.           chapter_num = self.chapter.xpath(
  8.               './/span[contains(@class, "chaptertitle")]/text()')[0]
  9.           # 去掉章节号最后的冒号
  10.           chapter_num = chapter_num[:-1]
  11.           # 章节名
  12.           chapter_name = self.chapter.xpath(
  13.               './/span[contains(@class, "chaptername")]/text()')[0]
  14.           return chapter_num, chapter_name
  15.       @property
  16.       def chapter_info(self):
  17.           self._chapter_info = self.parse_all()
  18.           return self._chapter_info
  19.      
  20.       def get_lessons(self):
  21.           return self.chapter.xpath(
  22.               './/div[@data-lesson]')
  23.   class Lesson:
  24.       def __init__(self, lesson):
  25.           self.lesson = lesson
  26.           self._lesson_info = None
  27.       @property
  28.       def lesson_info(self):
  29.           # 课时号
  30.           lesson_num = self.lesson.xpath(
  31.               './/span[contains(@class, "ks")]/text()')[0]
  32.           # 课时名
  33.           lesson_name = self.lesson.xpath(
  34.               './/span[@title]/@title')[0]
  35.           # 课时长
  36.           lesson_len = self.lesson.xpath(
  37.               './/span[contains(@class, "kstime")]/text()')[0]
  38.           self._lesson_info = lesson_num, lesson_name, lesson_len
  39.           return self._lesson_info
复制代码

最终结果
  最终结果保存为 courseinfo.csv,与主运行文件同路径。
[attach]134564[/attach]






欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2