爬虫-day04

文章目录

上篇

1. xpath案例-百度贴吧(重点)

需求说明

给定一个贴吧的名字,抓取该贴吧中,第一页中帖子的标题、帖子的详情页url地址,以及帖子详情页中图片的链接,最终要将图片保存到本地。

需要抓取的字段:

  • 帖子标题(title)
  • 帖子详情页url地址(detail_url)
  • 详情页所有图片url地址(img_url_list)

提取数据分析

# 获取所有帖子的标题
//ul[@id="thread_list"]/li//a[@class="j_th_tit"]/text()

# 获取所有帖子的详情页地址
//ul[@id="thread_list"]/li//a[@class="j_th_tit"]/@href

# 获取帖子详情页图片的地址
//img[@class="BDE_Image"]/@src

代码实现

import random
import time
import requests
from lxml import etree


class TiebaSpider(object):
    """百度贴吧爬虫类"""
    def __init__(self, tb_name):
        """
        tb_name: 贴吧的名称
        """
        # 准备贴吧 url 地址
        self.url = 'https://tieba.baidu.com/f?kw={}'.format(tb_name)

        # 准备请求头
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) '
                          'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
            'Cookie': '从浏览器抓包记录中复制的Cookie数据'
        }

        # 准备详情页基准地址
        self.base_url = 'https://tieba.baidu.com'

        # 准备保存提取数据的列表
        self.data_list = []

    def send_request(self, url):
        """发送请求,返回响应"""
        # 随机休眠0-1秒
        time.sleep(random.uniform(0, 1))
        response = requests.get(url, headers=self.headers)
        # 返回响应内容
        return response.content # bytes

    def parse_data(self, html):
        """
        提取每个帖子的数据
        html:指定贴吧的第一页响应的内容
        """
        # 将响应内容中的 html 注释去掉
        html_str = html.decode().replace('<!--', '').replace('-->', '')

        # 首先把 html_str 内容处理成 Element 对象
        element = etree.HTML(html_str)

        # 查询包含每个帖子 li 元素
        li_list = element.xpath('//ul[@id="thread_list"]/li')

        # 遍历每个帖子的 li 元素,提取每个帖子的标题、详情页地址,以及详情页的图片的地址
        for li in li_list:
            item = {}
            # 提取每个帖子的标题
            item['title'] = li.xpath('.//a[@class="j_th_tit "]/text()')[0] # list

            # 提取每个帖子的详情页地址
            item['detail_url'] = li.xpath('.//a[@class="j_th_tit "]/@href')[0]
            item['detail_url'] = self.base_url + item['detail_url']

            # 提取每个帖子的详情页图片地址
            item['img_url_list'] = self.parse_detail(item['detail_url'])

            print(item)

            # 保存提取帖子的信息
            self.data_list.append(item)

    def save_data(self):
        """保存帖子详情页图片"""
        for item in self.data_list:
            # 获取帖子的图片地址列表
            img_url_list = item['img_url_list']

            for img_url in img_url_list:
                # 发送请求
                img_response = self.send_request(img_url)

                # 保存文件
                filename = img_url[-20:]
                with open(filename, 'wb') as f:
                    f.write(img_response)

                print(f'{img_url} ---> 图片保存成功!')

    def parse_detail(self, url):
        """
        解析详情页图片地址
        url:帖子的详情页地址
        """
        # 先请求获取帖子详情页的内容
        detail_response = self.send_request(url)

        # 从详情页的内容中提取详情页引入图片的地址
        detail_element = etree.HTML(detail_response)  # bytes和str
        img_url_list = detail_element.xpath('//img[@class="BDE_Image"]/@src')
        return img_url_list

    def start(self):
        """启动爬虫的方法"""
        # 首先要抓取指定贴吧的第一页的内容
        html = self.send_request(self.url) # bytes

        # 补充:将 html 内容写入文件,验证和浏览器显示的内容是否一致
        with open('tieba.html', 'w', encoding='utf8') as f:
            f.write(html.decode())
            print('文件写入成功!')

        # 然后根据响应内容,提取页面上每个帖子的标题、详情页地址,以及详情页的图片的地址
        self.parse_data(html)

        # 请求详情页图片路径,将图片保存到本地
        self.save_data()


if __name__ == '__main__':
    # 输入贴吧名称
    tb_name = input('请输入贴吧名称:')
    # 创建百度贴吧的爬虫类的对象
    spider = TiebaSpider(tb_name)
    # 启动爬虫
    spider.start()

2. BeautifulSoup4使用

Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据,支持css选择器提取数据。

find_all方法

爬虫-day04
爬虫-day04

select方法

爬虫-day04
爬虫-day04
爬虫-day04

下篇

1. bs4案例-糗事百科爬虫(重点)

页面地址规律分析

第一页:https://www.qiushibaike.com/text/page/1/
第二页:https://www.qiushibaike.com/text/page/2/
第三页:https://www.qiushibaike.com/text/page/3/
...
第十三页:https://www.qiushibaike.com/text/page/13/

提取每个段子信息分析

# 查找到包含每个段子信息的 div 标签
div.col1.old-style-col1 > div

# 查找作者
段子的 div 下面 h2 标签文本

# 查找段子内容
段子的 div 下面 class='content' 的 div 标签中的文本

# 查找段子的好笑数
class='stats-vote' 的 span 标签下的 i 标签中的文本

# 查找段子的评论数
class="qiushi_comments" 的 a 标签下的 i 标签中的文本

代码实现

import json
import random
import time
import requests
from bs4 import BeautifulSoup


class QiuBaiSpider(object):
    """糗事百科爬虫类"""
    def __init__(self):
        # 准备糗事百科段子页面模板地址
        self.base_url = 'https://www.qiushibaike.com/text/page/{}/'

        # 准备请求头
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 '
                          '(KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'
        }

        # 准备保存段子页面地址的列表
        self.url_list = []

        # 准备保存段子信息的列表
        self.data_list = []

    def get_url(self):
        """生成糗事百科段子第1页-13页地址"""
        self.url_list = [self.base_url.format(i) for i in range(1, 14)]

    def send_request(self, url):
        """发送请求,获取响应"""
        # 控制频率
        time.sleep(random.uniform(0, 1))
        response = requests.get(url, headers=self.headers)
        html_str = response.content.decode()
        return html_str

    def parse_data(self, html_str):
        """响应的 html 数据进行解析"""
        # 创建 BeautifulSoup 对象
        soup = BeautifulSoup(html_str, 'lxml')

        # 查找到包含每个段子信息的 div 标签
        div_list = soup.select('div.col1.old-style-col1 > div')

        # 遍历每个 div 标签,获取每个段子的信息:作者、内容、好笑数、评论数
        for div in div_list:
            item = {}
            # 查找段子作者
            item['author'] = div.find('h2').get_text().strip()

            # 查找段子内容
            item['content'] = div.find('div', {'class': 'content'}).get_text().strip()

            # 查找段子好笑数
            item['funny_num'] = div.select('span.stats-vote > i')[0].get_text().strip()

            # 查找段子评论数
            item['comments'] = div.select('a.qiushi_comments > i')[0].get_text().strip()

            # 保存每个段子信息
            self.data_list.append(item)

    def save_data(self):
        """把提取的数据写入到文件中"""
        with open('qiubai.json', 'w', encoding='utf8') as f:
            # 将解析后的 list 数据处理格式化字符串
            # content = json.dumps(self.data_list, indent=2, ensure_ascii=False)
            # f.write(content)

            # 上面的两行代码等价于这一句
            json.dump(self.data_list, f, indent=2, ensure_ascii=False)

    def start(self):
        """启动爬虫的方法"""
        # 首先生成糗事百科段子第1页-13页地址
        self.get_url()

        # 遍历向每一页发送请求,获取每一页段子响应,并对响应的 html 数据进行解析
        for url in self.url_list:
            # 向每一页发送请求,获取每一页段子响应
            html_str = self.send_request(url)

            # 对响应的 html 数据进行解析
            self.parse_data(html_str)
            print(f'{url}------>解析完成!')

        # 最后将提取的段子的信息保存到文件中
        self.save_data()


if __name__ == '__main__':
    # 创建爬虫类的对象
    spider = QiuBaiSpider()
    spider.start()

2. selenium功能简介

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接控制浏览器工作。

使用步骤

1)下载 selenium

pip install selenium

2)下载对应浏览器的 webdriver 程序

谷歌浏览器的 webdriver 程序解压之后为:chromedriver

3. selenium 基本使用(重点)

百度搜索示例

爬虫-day04

driver对象的常见属性和方法

爬虫-day04
爬虫-day04

driver对象查找标签元素的方法

find_element_by_id                      (返回一个元素)
find_element(s)_by_class_name           (根据类名获取元素列表)
find_element(s)_by_name                 (根据标签的name属性值返回包含标签对象元素的列表)
find_element(s)_by_xpath                (返回一个包含元素的列表)
find_element(s)_by_link_text            (根据链接文本获取元素列表)
find_element(s)_by_partial_link_text    (根据链接包含的文本获取元素列表)
find_element(s)_by_tag_name             (根据标签名获取元素列表)
find_element(s)_by_css_selector         (根据css选择器来获取元素列表)

find_element 和 find_elements 的区别:

  • 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
  • find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表

标签元素对象的属性和方法

爬虫-day04

上一篇:day04 与用户交互; 格式化输出; 基本运算符;流程控制


下一篇:day04