Selenium之学习杂记(六)

网站分析

在对网站进行数据采集之前,我们要先看一下网站是否禁止我们的这种行为。打开猫眼电影的robots.txt看一看。网站一般都存在robots.txt,用于告诉爬虫和搜索引擎(实际上也是爬虫)哪些页面可以获取,哪些页面不可以获取。
在这里插入图片描述
采集猫眼电影的TOP100榜单。
这里有几个要获取的要素:“霸王别姬”,这是电影名;主演姓名,这也是要获取的内容;上映时间和电影的受欢迎程度并不存在具体的关联,所以不在我们考虑的范围内;电影的评分,客户肯定优先参考评分,所以也要获取该内容。但有了这些要素还远远不够,我们还需要通过以下代码获取电影的内容介绍。
先找到top100的地址,
在这里插入图片描述

分析一下:
活着

我们考虑用XPath来获取内容,找到共同规律后使用for循环拼接。先看一下XPath的规律。
//[@id=“app”]/div/div/div[1]/dl/dd[1]/div/div/div[1]/p[1]/a
//
[@id=“app”]/div/div/div[1]/dl/dd[2]/div/div/div[1]/p[1]/a
//[@id=“app”]/div/div/div[1]/dl/dd[3]/div/div/div[1]/p[1]/a
//
[@id=“app”]/div/div/div[1]/dl/dd[4]/div/div/div[1]/p[1]/a

其实大部分内容都相同,不同的是dd[]中的数字。一个页面上有10条数据,并且数据是从1开始编号的,而我们平常在Python中的range()函数是从0开始编号的,因此考虑使用range(1,11),即从1计数到10。因为需要获取的内容都在title标签中,所以我们可以使用get_attribute(“title”)方法来获取title属性中的文字。

再来看一看主演这部分内容怎么获取。
主演:葛优,巩俐,牛犇(bēn)

这里文字部分被包裹在标签中。我们考虑使用元素定位的方法找到元素的位置,然后获取标签中的文字。

9.0

关于评分的部分略微有些复杂:猫眼电影评分的整数部分在一个标签中,而小数部分又在一个标签中,但不管是整数部分还是小数部分,都在一个属性为score为p标签下。再来看一下主演和评分部分的XPath。
主演部分的XPath如下。
//[@id=“app”]/div/div/div[1]/dl/dd[1]/div/div/div[1]/p[2]
//
[@id=“app”]/div/div/div[1]/dl/dd[2]/div/div/div[1]/p[2]
//*[@id=“app”]/div/div/div[1]/dl/dd[3]/div/div/div[1]/p[2]

评分部分的XPath如下。
//[@id=“app”]/div/div/div[1]/dl/dd[1]/div/div/div[2]/p
//
[@id=“app”]/div/div/div[1]/dl/dd[2]/div/div/div[2]/p
//*[@id=“app”]/div/div/div[1]/dl/dd[3]/div/div/div[2]/p

我们可以用和刚才一样的XPath拼接方法来处理,再通过循环获取数据。但一页结束后,我们怎么进入下一页呢?再来分析一下猫眼电影的TOP100榜单的页面的URL。
在这里插入图片描述
为什么只有第一个页面不同?我们可以看到,每个页面的offset值在前一个页码的基础上增加了10,offset值刚好对应页面的数据条数。但第一个页面又有所不同,没有offset参数。我们进行一个大胆的猜测,第一个页面也有offset,只是offset的值为0,因此它没有显示。实践出真知,我们直接访问检验一下。确实是这样,加入offset参数后,我们仍然能进入第一个页面。

最初的测试代码

首先,导入库。导入的库是本书主要使用的Selenium和Time模块。使用Time模块,而不使用显式等待,主要是为了让爬虫更像一个“人”,以免爬虫过快的访问给浏览器带来困扰。

然后,我们从整体上来看TOP100榜单。因为每个页面有10条数据,所以我们需要构建10个页面链接。当然,根据个人爱好,将每个页面访问一遍再把URL复制下来也可以。这里使用列表,然后进行URL拼接,并写入列表中。这样列表中一共有10个元素(URL)。接下来,再次使用for循环,对列表中的每个页面都通过XPath获取标题、分数、演员。最后,打开页面,获取电影的内容介绍
代码

# 导入库
from selenium import webdriver
import time

# 每一页的offset值的列表
number_list = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
# 设置要访问的url地址空列表
url_list =[]
# for循环拼接需要访问的url地址列表,加入到url_list
for i in number_list:
    url = "https://maoyan.com/board/4?offset=%d" %i
    url_list.append(url)
    print("获取的地址:%s" %url)

# 设置webdriver启动的浏览器
driver = webdriver.Chrome()

# 循环调用url_list中的url
for i in url_list:
    driver.get(i)
    time.sleep(1)
    for j in range(1, 11):
        # 获取演员
        player_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[1]/p[2]' %j
        player = driver.find_element_by_xpath(player_xpath).text
        # 获取分数
        score_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[2]/p' %j
        score = driver.find_element_by_xpath(score_xpath).text
        # 获取标题
        title_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[1]/p[1]/a' %j
        title = driver.find_element_by_xpath(title_xpath).get_attribute('title')
        # 获取电影介绍
        driver.find_element_by_xpath(title_xpath).click()
        introduce_xpath = '//*[@id="app"]/div/div[1]/div/div[3]/div[1]/div[1]/div[2]/span'
        introduce = driver.find_element_by_xpath(introduce_xpath).text
        print('电影标题:%s' %title)
        print('主要演员:%s' %player)
        print('分数:%s' %score)
        print(introduce)
        driver.get(i)
# 关闭
driver.close()

代码执行结果如下:
在这里插入图片描述
满足如下流程
在这里插入图片描述

进一步完善之后的测试代码

既然能够输出结果了,我们就再对刚才的代码进行一次修改,将其写入CSV文件中。为什么使用CSV文件,而不使用数据库呢?首先,我们的数据比较少,没有大型的存储需求。其次,对于小型项目来说,我们创建数据库,创建表,然后写入、查询和检验,这一套流程耗费的时间和精力可能比我们写爬虫程序本身耗费的时间和精力还多。数据库的功能很强大,但应用在这种场景下就显得有些大材小用了。修改之后的源代码如下。
修改之后的源代码如下。

# 导入库
from selenium import webdriver
import time
import csv
# 每一页的offset值的列表
number_list = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
# 设置要访问的url地址空列表
url_list =[]
# for循环拼接需要访问的url地址列表,加入到url_list
for i in number_list:
    url = "https://maoyan.com/board/4?offset=%d" %i
    url_list.append(url)
    print("获取的地址:%s" %url)

# 设置webdriver启动的浏览器
driver = webdriver.Chrome()
# 打开CSV文件
csv_file = open('writer.csv', 'w+', newline="", encoding='utf-8-sig')
writer = csv.writer(csv_file)
# 循环调用url_list中的url
for i in url_list:
    driver.get(i)
    time.sleep(1)
    for j in range(1, 11):
        # 获取演员
        player_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[1]/p[2]' %j
        player = driver.find_element_by_xpath(player_xpath).text
        # 获取分数
        score_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[2]/p' %j
        score = driver.find_element_by_xpath(score_xpath).text
        # 获取标题
        title_xpath = '//*[@id="app"]/div/div/div[1]/dl/dd[%d]/div/div/div[1]/p[1]/a' %j
        title = driver.find_element_by_xpath(title_xpath).get_attribute('title')
        # 获取电影介绍
        driver.find_element_by_xpath(title_xpath).click()
        introduce_xpath = '//*[@id="app"]/div/div[1]/div/div[3]/div[1]/div[1]/div[2]/span'
        introduce = driver.find_element_by_xpath(introduce_xpath).text
        # 拼接
        text = []
        text.append(title)
        text.append(player)
        text.append(score)
        text.append(introduce)
        # 写入CSV文件中
        writer.writerow(text)
        print("-------------------正在获取第%s条" %j)
        # 返回初始页面
        driver.get(i)
        time.sleep(1)
# 最后输出和关闭
print("all_done")
driver.close()

执行结果:
在这里插入图片描述
在这里插入图片描述
我们在打开CSV文件的时候使用到了UTF-8-SIG编码。对于大部分读者来说,这种编码可能很新,甚至是第一次看到。为什么要使用UTF-8-SIG编码?UTF-8-SIG编码即UTF-8 with BOM。我们如果将UTF-8-SIG换为UTF-8,就会发现我们存储的CSV文件虽然可以用记事本打开,但如果用Excel打开就会出现乱码,为什么呢?因为Excel读取CSV文件的时候是通过读取文件头上的BOM(Byte Order Mark,字节顺序标记)来识别编码的,并且按照Unicode编码来识别没有BOM的文件。注意,BOM是一种文件头部协议,存储在文件头部,用于标识文件编码。然而,我们生成的CSV文件没有BOM,Excel自动按照Unicode编码规则进行读取,但该文件的编码却不是使用Unicode的,所以会出现编码问题。如前所述,作为开发人员,必须彻彻底底地弄清楚编码问题,甚至有时候要推翻自己原先认为对的东西。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值