首页 > 其他分享 >pathon爬虫实战——爬取某网站的多页番剧内容

pathon爬虫实战——爬取某网站的多页番剧内容

时间:2023-04-19 20:23:51浏览次数:41  
标签:pathon content img xpath 爬取 html print 番剧 append

(本博客只为技术分学习,无其他用途)


 

1.准备

涉及的第三方库如下:

 

2.网页分析

2.1 检验网页

1. 运行浏览器,打开网页,按快捷键F12打开开发者工具,F5刷新页面

2. 在右侧点击Network,打开browser?sort=rank&page=1 文件,可以看到各种信息,查看表头

 

3. 获取Cooki 和User-Agnet,准备伪装浏览器

 

cooki = {
    'Cooki':'chii_sid=9d93vQ; chii_sec_id=A56jP7ywgsTIyHVgRdkNaKLWSr78u1GyIrwvbA; chii_theme=light; __utma=1.22392930.1681741390.1681741390.1681741390.1; __utmc=1; __utmz=1.1681741390.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmt=1; _ga=GA1.1.1822559156.1681741390; chii_cookietime=0; chii_auth=U8%2Bgbe6%2BiJDdyyVqQNkHI%2FuCHsKf8GWIQb8JdwidsW7q0xwNW5HYfQLMVqJYAGl9SZsfA5o4RYtgWU0SpRtCYczS5gmQSyu%2FitIq; __utmb=1.11.10.1681741390; _ga_1109JLGMHN=GS1.1.1681741390.1.1.1681741903.0.0.0'
}
head = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 SLBrowser/8.0.1.4031 SLBChan/25 ',
    'Connection': 'close'}  # 当前正在使用的tcp链接在当天请求处理完毕后会被断掉

 

  

 

4.使用Requests发送GET请求

定义function:

 

# 获取网址请求
def get_url(url):
    response = requests.get(url=url, timeout=600, cookies=cooki, headers=head,
                            verify=False)  # 用verify关键字参数,在请求的时候不验证网站的ca证书
    data = response.text.encode('ISO-8859-1').decode(
        'utf-8')  # Python 终端的编码方式是 UTF-8 ,而 HTML 编码方式并不是 UTF-8 (可通过 response.encoding 查询页面编码格式),为了避免在匹配标题时中文产生了乱码
    html = etree.HTML(data)  # 解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象

    return html

 

  

 

5.xpath语法

推荐这个博主的讲解

(120条消息) 史上最全的xpath定位方法 全在这了!_七月的小尾巴的博客-CSDN博客

 

 

 

2.2 网址页面分析

第一页:

第二页:

由此可知页面的切换与 page 有关,第N页的网址只要修改为 https://--------------------page = N 

  由此获取100条网址的列表:

urls = [('https://bangumi.tv/anime/browser?sort=rank&page=' + f'{x}') for x in range(1, 101)] # 网址列表       2.3 xpath 元素分析 每个番剧的元素设计模式都是相似的,找出模式再利用xpath分析即可获取 1.分析id

 

 定位标签,xpath语句:

    id_content = html.xpath('//div[@class = "section"]/ul/li/@id')

定义function:

# 匹配id
def get_id(html):
    id_content = html.xpath('//div[@class = "section"]/ul/li/@id')  
    for i in id_content:
        if i:  # 判断是否为空
            id.append(i)
        else:
            id.append('None')

  

2. 链接分析

 

 定位标签,xpath语句:

    link_content = html.xpath('//div[@class = "section"]/ul/li/a/@href') 

 获取的网址还是残缺的,要加上前缀

定义function:

# 匹配链接
def get_link(html):
    link_content = html.xpath('//div[@class = "section"]/ul/li/a/@href')
    for lk in link_content:
        link.append('https://bangumi.tv/' + lk)  # 组合链接网址并存储

 

3.图片分析

 

 定位标签,xpath语句:

 img_content = html.xpath('//span[@class ="image"]/img/@src')

 图片有两种类型jpg和png,用split分割获取图片类型,地址还是残缺的,根据图片类型加上不同的前缀

定义function:

# 获取图片地址
def get_img_link(html):
    img_content = html.xpath('//span[@class ="image"]/img/@src')
    for i in img_content:
        if i:
            tile = str(i).split('.')[-1]  # 获取图片类型
            if tile == 'jpg':  # 如果为jpg图片
                img.append('https:' + str(i))  # 组合图片网址并存储
            if tile == 'png':  # 如果为png图片
                img.append('https://bangumi.tv' + str(i))  # 组合图片网址并存储

  

4.排名分析

 

 定位标签,xpath语句:

    rank_content = html.xpath('//span[@ class ="rank"]/text()') 

 有时候会返回空字符串,所以要判断处理以下再存入列表

定义function:

# 匹配排名
def get_rank(html):
    rank_content = html.xpath('//span[@ class ="rank"]/text()')
    for r in rank_content:
        if r:  # 判断是否为空
            rank.append(r)
        else:
            rank.append('None')

  

5.番名分析

 

 定位标签,xpath语句:

    name_content = html.xpath('//h3/a[@class = "l"]/text()')

 

有时候会返回空字符串,所以要判断处理以下再存入列表  

定义function:

# 匹配番名
def get_name(html):
    name_content = html.xpath('//h3/a[@class = "l"]/text()')
    for n in name_content:
        if n:  # 判断是否为空
            name.append(n)
        else:
            name.append('None')

 

 

 

 

6.信息分析(包括集数,日期,创作人员)

 

 定位标签,xpath语句:

   information_content = html.xpath('//p[@ class ="info tip"]/text()')

返回的信息以split以‘/’分割两次,获取三段数据,分别为集数、日期、制作人员,判断是否空分再别存入对应的列表

定义function:

# 匹配信息
def get_infor(html):
    information_content = html.xpath('//p[@ class ="info tip"]/text()')
    for i in information_content:
        i = str(i).split('/', 2)  # 将数据类型转换为字符串且以‘/’分割两次

        # 某些数据有残缺,要判断元素个数
        if len(i) == 1:
            episode.append(i[0].strip())  # 提取集数即列表的第一个元素,去除空格
            date.append('未知')
            creator.append('未知')

        if len(i) == 2:
            episode.append(i[0].strip())  # 提取集数即列表的第一个元素,去除空格
            date.append(i[1].strip())  # 不为空则提取日期即列表的第二个元素,去除空格
            creator.append('未知')

        if len(i) == 3:
            episode.append(i[0].strip())  # 提取集数即列表的第一个元素,去除空格
            date.append(i[1].strip())  # 提取日期即列表的第二个元素,去除空格
            creator.append(i[-1].strip())  # 提取创作人员即列表的最后一个元素,去除空格

  

 

7. 评分分析

 

 定位标签,xpath语句:

    rating_content = html.xpath('//small[@ class ="fade"]/text()')

  

定义function:

# 匹配评分
def get_rating(html):
    rating_content = html.xpath('//small[@ class ="fade"]/text()')
    for r in rating_content:
        if r:  # 判断是否为空
            rating.append(r)
        else:
            rating.append("None")

  

 

8. 评价人数分析

 

   定位标签,xpath语句:

    person_content = html.xpath('//span[@class ="tip_j"]/text()')

  

定义function:

# 匹配评价人数
def get_person(html):
    person_content = html.xpath('//span[@class ="tip_j"]/text()')
    for p in person_content:
        if p:  # 判断是否为空
            person.append(p)
        else:
            person.append('None')

  

9.下载单个图片

先判断图片类型再以不同方式命名图片,将图片以二进制模式写入到到目标文件目录下

定义function:

# 下载单个图片
def download_img(address):
    path = os.path.abspath('Image')  # 获取文件夹当前绝对路径
    t = address.split('.')[-1]  # 获取图片类型
    if t == 'jpg':
        picture_name = 'item_' + address.split('/')[-1].split('_')[0]  # 获取id数字
        file_name = path + '\{name}.jpg'.format(name =picture_name)  # 设置文件名
        t = random.uniform(2, 8)  # 定义随机暂停时间
        img_response = requests.get(address)
        time.sleep(t)
        with open(file_name, 'wb') as f:
            f.write(img_response.content)  # 以二进制格式写入图片
            print('图片下载完成')
    if t == 'png':
        file_name = path + r'\None.png'  # 设置文件名
        t = random.uniform(2, 8)  # 定义随机暂停时间
        img_response = requests.get(address)
        time.sleep(t)
        if not os.path.exists(file_name):
            with open(file_name, 'wb') as f:
                f.write(img_response.content)  # 以二进制格式写入图片
                print('图片下载完成')

  

 

 

 

 

 

3.线程池

推荐这位博主的讲解

python并发编程之多线程和线程池 - 掘金 (juejin.cn)

 

Exectuor 主要方法:

  • submit(fn, *args, **kwargs):将 fn 函数提交给线程池。*args 代表传给 fn 函数的参数,*kwargs 代表以关键字参数的形式为 fn 函数传入参数。

推荐这位博主的讲解:

python线程池 ThreadPoolExecutor 使用详解_生活不允许普通人内向的博客-CSDN博客

定义function:

# 线程池
def thread_pool():
    thread_results = []
    urls = [('https://bangumi.tv/anime/browser?sort=rank&page=' + f'{x}') for x in range(1, 101)]  # 网址列表
    with ThreadPoolExecutor() as pool:  # 创建线程池
        futures = [pool.submit(get_url, url) for url in urls]   # 将get_url函数递交给线程池,传入参数为url
    for future in as_completed(futures):  # 按线程完成顺序返回,先完成先返回
        thread_results.append(future.result())  # 获取任务返回值

    return thread_results

  

 

 

 

4. 执行函数

# 执行函数
if __name__ == "__main__":
    spider_start = time.time() # 计时爬虫开始
    results = thread_pool()  # 接收函数返回值
    for result in results:  # 调用函数
        get_id(result)
        get_link(result)
        get_rank(result)
        get_name(result)
        get_img_link(result)
        get_infor(result)
        get_rating(result)
        get_person(result)
    spider_end = time.time() #计时爬虫结束
    print(f'爬取数据消耗了{spider_end-spider_start}')
    print(id, '\n', len(id))  # 打印爬取结果
    print(link, '\n', len(link))
    print(img, '\n', len(img))
    print(rank, '\n', len(rank))
    print(name, '\n', len(name))
    print(episode, '\n', len(episode))
    print(date, '\n', len(date))
    print(creator, '\n', len(creator))
    print(rating, '\n', len(rating))
    print(person, '\n', len(person))

  

 

 

5. 数据库操作

1. 创建表

CREATE TABLE Anime (
	Id VARCHAR (100 ) NOT NULL PRIMARY KEY,
	Link VARCHAR ( 100 ),
	Name_anime VARCHAR ( 100 ),
	Rank_anime CHAR ( 50 )  ,
	Episode VARCHAR ( 100 ) ,
	Date_time VARCHAR ( 300 ),
	Creator VARCHAR ( 200 ) ,
	Rating FLOAT ( 10 ) ,
	Person_num CHAR ( 40 ) ,
	Mark CHAR ( 10 ) 
);

2.执行sql语句,插入数据

    # 创建数据库连接
    sql_start = time.time()  # 计时数据插入开始
    db = pymysql.connect(host='localhost',
                         user='root',
                         password='318427',
                         database='animeplan')

    # 使用cursor()方法获取操作游标
    cursor = db.cursor()
    sql = """
    insert into anime(Id,Link,Name_anime,Rank_anime,Episode,Date_time,Creator,Rating,Person_num)
    values (%s,%s,%s,%s,%s,%s,%s,%s,%s)
    """
    # 循环插入数据
    for num in range(len(id)):
        try:
            cursor.execute(sql, (
                id[num], link[num], name[num], rank[num], episode[num], date[num], creator[num], rating[num],
                person[num]))

            db.commit()
            print('数据插入成功')
        except Exception as e:
            print(e)
            print('数据插入错误')

    db.close()
    sql_end = time.time()  # 计时数据插入结束
    print(f'插入数据消耗了{sql_end-sql_start}')

  

6. 启用线程池爬取图片

   # 下载图片
    try:
        img_start = time.time()
        if os.path.exists('Image'):  # 判断路径存在
            print('Image文件夹已经创建,开始下载图片')
            with ThreadPoolExecutor() as image_poll:  # 创建线程池
                image_futures = [image_poll.submit(download_img, address) for address in img]  # 递交download_img函数,传入address图片地址
            for im_future in image_futures:
                print(f'{im_future.done()}')  # 返回任务执行状态,判断该任务是否结束

        else:
            print('建立Image文件夹,开始下载图片')
            os.mkdir('Image')  # 创建文件夹来存储图片文件
            with ThreadPoolExecutor() as image_poll:
                image_futures = [image_poll.submit(download_img, address) for address in img]
            for im_future in image_futures:
                print(f'{im_future.done()}')
        img_end = time.time()
        print(f'花费了{img_end - img_start}')
    except Exception as e:
        print(e, '\n', '图片下载失败')

  

 

 

 

 

 

 

 

警告:

本文只是用于技术学习,绝无其他用途!

读者不可用于其他用途,后果自负!

 

标签:pathon,content,img,xpath,爬取,html,print,番剧,append
From: https://www.cnblogs.com/Mokirito/p/17334497.html

相关文章

  • 记一次python写爬虫爬取学校官网的文章
    有一位老师想要把官网上有关数字化的文章全部下载下来,于是找到我,使用python来达到目的首先先查看了文章的网址获取了网页的源代码发现一个问题,源代码里面没有url,这里的话就需要用到抓包了,因为很明显这里显示的内容是进行了一个请求,所以只能通过抓包先拿到请求的url从而获得每一......
  • selenium爬取异步加载的网站
    为了便利化使用selenium驱动浏览器进行操作,遇到一个网页,大部分内容都是通过xhr请求后再通过前端js处理显示,带来的一个问题就是,采用显示等待无法准确的定位到需要的节点。因此,需要考虑采用判断xhr请求是否完成后再进行定位,或者直接获取xhr请求返回内容的做法。对于selenium爬虫来说,......
  • 批量爬取TXT文本
    importreimportos #导入模块importthreadingimportpymysql#连接数据框,创建表db=pymysql.connect(host='localhost',user='root',password='1234',database='旅游�......
  • 爬取的数据存mysql中、加代理,cookie,header,加入selenium、布隆过滤器、scrapy-redis实
    上节回顾#1scrapy架构 -爬虫:写的一个个类-引擎: -调度器:排队,去重-下载器-pipline-下载中间件-爬虫中间件#2命令 -scrapystartproject项目名-scrapygensipder爬虫名网址-scrapycrawl爬虫名字-run.py#......
  • Python爬虫之多线程加快爬取速度
    之前我们学习了动态翻页我们实现了网页的动态的分页,此时我们可以爬取所有的公开信息了,经过几十个小时的不懈努力,一共获取了16万+条数据,但是软件的效率实在是有点低了,看了下获取10万条数据的时间超过了56个小时,平均每分钟才获取30条数据。注:软件运行的环境的虚拟主机,CPU:......
  • python爬虫(四):文本、图片、视频爬取实例
    上篇讲了常用的python爬虫工具,可以快速支撑我们数据的爬取--解析--分析,这里将拆解几个爬虫程序实例进行学习,实例来自于https://cuijiahua.com/blog/2020/04/spider-6.html的系列教程或者其他小爬虫;一、文本图表数据抓取(编程语言排名)#!/usr/bin/envpython#coding:utf-8importr......
  • Python爬虫之循环爬取多个网页
    之前的文中介绍了如何获取给定网址的网页信息,并解析其中的内容。本篇将更进一步,根据给定网址获取并解析给定网址及其相关联网址中的内容。要实现这些功能,我们需要解决以下问题:1、如何持续不断的获取url,并读取相关内容。2、如何判断网址是否已经读取过。文中用到的代码均已上传......
  • python爬虫案列11:爬取双色球历史开奖记录并存储到mysql
    开始之前要先在MySQL创建一个名为spider的数据库,在里面创建一个名caipiao的表,表里面三个字段,data,red,blue点击查看代码importrequestsimportpymysqlfromlxmlimportetree#连接数据库conn=pymysql.connect(host='localhost',port=3306,user='root',password='......
  • 爬取腾讯漫画_网球王子
    一,通过Selenium模块完成自动化获取图片importtime#time时间模块用于延时等待importos#os模块调用系统模块创建目录importrequests#发送请求模块fromseleniumimportwebdriver#导入selenium包fromselenium.webdriver.chrome.serviceimportService#导......
  • 爬取BOSS直聘信息selenium+CSS及总结
    1、fromseleniumimportwebdriverfromselenium.webdriver.common.byimportByimporttimeimportcsvf=open(r'D:\Pyprogram\venv\从零开始学python网络爬虫\爬取BOOS直聘.csv','wt',newline='',encoding='utf-8')writer=csv.wri......