返回介绍

7.4 爬取新浪微博网站

发布于 2025-04-21 19:15:27 字数 6841 浏览 0 评论 0 收藏

7.4.1 新浪微博网站爬取分析

爬虫实战-Selenium 登录并爬取微博首页

这一节通过爬取新浪微博网站这个实例来讲解使用 Selenium 爬取动态网页的技巧。在编写代码之前,还是先分析一下新浪微博网站。

要爬取个人首页,首先需要登录新浪微博,由于 Selenium 使用浏览器登录,浏览器会自动帮用户处理 Cookies 并保持登录,因此,登录之后就可以直接打开微博的个人页面并爬取最新的微博了。

在浏览微博的时候,如果希望查看更多微博,需要向下拉动网页的滚动条,网页会自动加载更多的微博内容,如果希望爬虫下载更多微博,就需要模拟拉动滚动条这个动作。如果希望爬虫能够不断地爬取最新发布的微博,可以在等待一段时间后直接重新打开首页,然后爬取即可。

总结起来,爬取新浪微博页面,需要 3 步:第一步,登录新浪微博网站;第二步,解析微博网站页面;第三步,定时重新打开微博首页,爬取最新发布的微博或拉动滚动条爬取更多以前的微博。

下面按照这 3 步编写新浪微博网站爬虫代码。

7.4.2 新浪微博网站爬虫实现

第一步,导入需要的模块、编写保存函数。因为微博内容可能包含各种各样的表情符号从而引起保存错误,可以进行简单处理,使用 try 和 except 忽略保存错误。对于本书前面几章的代码,如果想让代码在遇到错误时能继续爬行,也可以像这样简单处理,增加 try 和 except。

from selenium import webdriver
import csv 
import time 
 
 
def csv_writer(item): 
    with open('weibo.csv', 'a', encoding='gbk', newline='') as csvfile: 
        writer=csv.writer(csvfile) 
        try: 
            writer.writerow(item) 
        except: 
print('写入失败') 

第二步,编写登录新浪微博网站的函数。

def login():
    driver.get('https://weibo.com') 
    time.sleep(5) 
    driver.set_window_size(1920, 1080)  #设置浏览器大小 
    #找到用户名输入框 
    username = driver.find_element_by_xpath('//*[@id="loginname"]')     
    username.send_keys('your username')   #填写用户名 
    password = driver.find_element_by_name('password') 
    password.send_keys('your password')   #填写密码 
    submit = driver.find_element_by_xpath( 
      '//*[@class="W_btn_a btn_32px"]')    #找到登录按钮 
    print('准备登录....') 
    submit.click()    #单击登录 
    time.sleep(4)

在登录函数中,首先使用 driver.get 方法打开微博网站首页,然后使用 set_window_size 方法设置窗口的大小,这样做的目的是防止默认的窗口大小下有些元素显示不全;然后使用 XPath 路径分别查找和填写登录用户名和密码;最后允许用户单击登录按钮提交登录。这里使用 time.sleep() 这种固定时长的等待方式。

第三步,定义爬取、解析页面函数。这里爬取微博发布者、发布者个人主页 URL 和发布的微博内容。

def spider():
    driver.get('https://weibo.com')    #刷新微博网站首页 
    time.sleep(4) 
    #先获取页面中所有微博代码段,然后使用循环从每一段中提取数据 
    all_weibo = driver.find_elements_by_xpath( 
      '//div[@class="WB_cardwrap WB_feed_type S_bg2 WB_feed_like"]') 
    for weibo in all_weibo: 
        pub_id = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[1]/a[1]')[0].text    #解析出微博用户 id 
        pub_id_url = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[1]/a[1]')[0].get_attribute('href')  
                                                 #解析发布者 URL 
        pub_content = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[3]')[0].text    #解析微博内容 
        item = [pub_id, pub_id_url, pub_content] 
        print('成功抓取', pub_id) 
csv_writer(item) 

下面详细解释一下 spider 函数。现在页面中有很多条微博,这里还是先抓取每一条微博的代码段,然后从这一代码段中解析发布者名称、发布者 URL、微博内容。Selenium 中使用.text 这种方法提取文本信息,使用.get_attribute 提取属性信息,最后使用 csv_write 函数保存抓取到的内容。

第四步,编写主函数。主要是初始化 driver 对象,然后每隔 5 分钟刷新一次页面,抓取最新发布的微博。

if __name__ == '__main__':
    driver = webdriver.Chrome(r'd:/selenium/chromedriver.exe') 
    login()    #先执行登录 
    while True: 
        spider() 
time.sleep(300)     #每隔 5 分钟执行 spider 函数 

以上是简单编写的新浪微博网站爬虫,它会登录新浪微博并每隔 5 分钟刷新一次页面,爬取最新发布的微博。这样并不是很完善,有可能 5 分钟没有刷新出来几条新微博,持续的抓取就会发生重复抓取的问题。同时,上面代码没有考虑去重,爬取过程中可能产生大量重复数据。

7.4.3 爬虫的简单去重

爬虫实战-Phontomjs 的使用

如何实现爬取数据的去重呢?可以借助 Python 的 set 数据结构实现对内容的简单去重,也可以基于微博时间线去重,甚至可以爬取下来后统一去重。下面演示最常见的使用 Python 的 set 数据结构进行去重的方法。

这里选择使用微博内容进行去重判断,毕竟一个微博用户可以多次发微博,不能用微博用户 id 或者用户 URL 进行去重判断。可以直接将爬取到的微博内容加进 set 中,然后每次爬取新的微博后进行是否重复的判断。这样做有一个坏处,那就是微博内容一般比较多,直接使用微博内容去重会占用大量的内存,影响爬虫效率。建议是使用摘要算法把微博内容转换成固定长度的摘要,然后对摘要是否重复进行判断。

什么是摘要算法呢?摘要算法又被称为哈希算法,它通过一个函数把任意长度的数据转换为一个长度固定的数据串(通常用 16 进制的字符串表示)。例如微博内容是一个很长的字符串,使用摘要算法会得到一个固定长度的摘要,如果一段时间后再次爬取到了这条微博,对它使用摘要算法会计算出相同的摘要;如果再次爬取的微博内容有变化,计算出的摘要会不同于原始微博的摘要。

可见摘要算法就是通过摘要函数对任意长度的数据(微博)计算出固定长度的摘要,然后就可以对摘要进行去重判断了。摘要算法之所以能指出数据是否相同,就是因为摘要函数是一个单向函数,计算摘要很容易,但通过摘要反推原始内容是非常困难的。同时,对原始数据做一个 bit 的修改,都会导致计算出的摘要完全不同。对于爬虫去重来说,使用摘要算法能大大减少内存占用,因为无论多长的微博内容,假如使用最常见的 MD5 摘要算法,都会被映射到固定的 128 bit。

这里以 MD5 摘要算法为例,计算出一个字符串的 MD5 值,导入 hashlib。hashlib 是一个提供了一些流行的 hash 算法的 Python 标准库。

>>>import hashlib
>>>str_md5 = hashlib.md5('life is short you need  
python'.encode('utf-8')).hexdigest()   #计算字符串 MD5 值 
>>>print(str_md5) 
'97c1a34bf007432144dfb14bbfb4fbb6' 

可以看到计算 MD5 值比较简单,唯一要注意的是在计算摘要之前,需要将字符串编码为二进制形式。

下面改造新浪微博爬虫代码,使它具有去重的功能。主要改两个地方,一是程序运行开始时,初始化一个 set。

if __name__ == '__main__':
    is_dup = set()       #新建一个空的 set 
    driver = webdriver.Chrome(r'd:/selenium/chromedriver.exe') 
    login() 
    while True: 
        spider() 
time.sleep(300) 

二是改造 spider 函数。爬取到数据后,在调用 csv_write 保存之前增加去重判断。

def spider():
    driver.get('https://weibo.com') 
    time.sleep(5) 
    all_weibo = driver.find_elements_by_xpath( 
      '//div[@class="WB_cardwrap WB_feed_type S_bg2 WB_feed_like"]') 
    for weibo in all_weibo: 
        pub_id = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[1]/a[1]')[0].text 
        pub_id_url = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[1]/a[1]')[0].get_attribute('href') 
        pub_content = weibo.find_elements_by_xpath( 
          'div[1]/div[3]/div[3]')[0].text 
#下面计算爬取到的 pub_content 摘要 
        hash_content = hashlib.md5(pub_content.encode('utf-8')).hexdigest() 
#如果摘要不在 set 中,就将爬取到的微博保存下来 
        if hash_content not in is_dup:  
            item = [pub_id, pub_id_url, pub_content] 
            print('成功抓取:', pub_id) 
            csv_writer(item) 
is_dup.add(hash_content)     #最后把保存过的微博摘要加进 set 中 

经过上面的改造,爬虫增加了去重判断,仅会对新的微博内容进行保存。这种去重并不是很完美,如果爬虫程序遇到问题中断或者服务器重启,set 中的内容会全部丢失,不能继续进行去重判断。如果希望将 set 中的内容持久化,可以考虑使用 Redis 缓存服务器去重,后面的 Scrapy 章节将介绍使用 Redis 缓存服务器去重的方法。

7.4.4 使用 Chrome 浏览器的 headless 模式

上面的爬虫在运行的时候会实际打开 Chrome 浏览器,这种方式执行效率不高,Chrome 浏览器 59 以上版本可以使用 headless 模式。所谓 headless 模式,就是在无界面模式下运行谷歌浏览器,本质就是将由 Chromium 和 Blink 渲染引擎提供的所有现代网页平台的特征,都转化成命令行模式执行。为了开启 Chrome 浏览器的 headless 模式,可以使用如下代码初始化 webdriver。

if __name__ == '__main__':
  chrome_options = ChromeOptions() 
  chrome_options.add_argument('--ignore-certificate-errors') 
  chrome_options.add_argument('--headless') 
  chrome_options.add_argument('--disable-gpu') 
  #binary_location 指向谷歌浏览器的安装路径 
  chrome_options.binary_location = (r'C:\Program Files(x86)\Google' 
                                    + r'\Chrome\Application\chrome.exe') 
  driver = webdriver.Chrome( 
    executable_path=r'd:\selenium\chromedriver.exe',  
    options=chrome_options)

上面代码中的 chrome_options.binary_location 要指向 Chrome 浏览器的安装路径,不同的系统有不同的路径,这里要根据自己使用的系统设置一下。--disable-gpu 是用来处理一些 bug 时暂时需要的命令,在之后的 Chrome 浏览器版本中就不需要了。

这样初始化 webdriver 后,就可以进入 headless 模式了。用户可以继续运行上面新浪微博的代码,但不会看到实际打开浏览器等一系列的操作。这种模式下爬虫的执行效率更高,如果使用隐式等待或者显式等待替换掉固定时长等待,整个爬虫的爬取效率可大大提高。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。