收集豆瓣电影 TOP250 信息

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
"""
豆瓣电影
1. 构造 requests 抓取网页源代码
2. 对源码进行正则表达式分析
3. 提出数据,直接显示或者存储进文件中
"""

import re
import requests

f = open("top250.csv", mode="w", encoding='utf-8')

url = "https://movie.douban.com/top250"

headers = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36'
}

for i in range(0, 251, 25):
    params = {
        'start': str(i),
        'filter': '',
    }

    resp = requests.get(url, headers=headers, params=params)
    pageSource = resp.text
    """
    排名: xx
    电影名: xxx
    评分: xx
    点评: xxxx
    """
    obj = re.compile(
        r'<div class="item">.*?<em class="">(?P<rank>.*?)</em>.*?<span class="title">(?P<name>.*?)</span>.*?property="v:average">(?P<score>.*?)</span>.*?<span class="inq">(?P<appraisal>.*?)</span>',
        re.S)
    result = obj.finditer(pageSource)
    for item in result:
        rank = item.group("rank")
        # print("排名: " + rank)
        name = item.group("name")
        # print("电影名: " + name)
        score = item.group("score")
        # print("评分: " + score)
        appraisal = item.group("appraisal")
        # print("点评: " + appraisal + '\n')
        f.write(f"{rank},{name},{score},{appraisal}\n")

f.close()
resp.close()
print("豆瓣电影 TOP250 信息收集完毕")

收集实习僧--信息安全实习岗位信息

参考文章:python爬虫爬取实习僧岗位信息并存入excel数据表中

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
"""
爬取实习僧--信息安全实习岗位

1. 爬取代码源数据存储至 html 文件中,参考源代码与页面对应的位置
f = open("reference.html", mode="w", encoding='utf-8')
f.write(resp.text)
2. 爬取过后,实习僧可能会禁用爬取的 IP 一段时间,此时可以在 html 文件中做参考(也可以使用代理池,但目前我不会)
f = open("reference.html", mode="r", encoding='utf-8')
data = f.read()
3. 查阅了大佬的博客发现数字是加密了的,需要相关文件解密,源代码相关内容如下
@font-face {    font-family: myFont;    src: url(/interns/iconfonts/file?rand=0.8686403770606255);}
4. 将下载的字体文件放进同目录文件下,重命名后缀为 .ttf,并解析成 xml 文件
from fontTools.ttLib import TTFont
font = TTFont("file.ttf")
font.saveXML("font.xml")
5. 使用表达式提取并转换对应的 HTML 实体,做一个字典,并做一个用于转换的函数
6. 将提取出的数据整合,并存储进 md 文件中

PS: 实习僧的加密字体文件每天都会变化,因此可以选择制作一个自动化脚本实现下载解密文件 + 解析 xml 文件 + 爬取网页信息并整合,但我嫌麻烦,所以就手动下载了
"""

import re
import requests


def get_dict():
    # 打开并读取 font.xml
    with open('font.xml') as f:
        xml = f.read()
    f.close()

    # 正则表达式提取 code 和 name
    keys = re.findall('<map code="(0x.*?)" name="uni.*?"/>', xml)
    values = re.findall('<map code="0x.*?" name="uni(.*?)"/>', xml)

    word_dict = {}
    # 将 name 解码成中文并作为值写入字典 word_dict,该字典的键为 keys
    for i in range(len(values)):
        if len(values[i]) < 4:
            values[i] = ('\\u00' +
                         values[i]).encode('utf-8').decode('unicode_escape')
        else:
            values[i] = ('\\u' +
                         values[i]).encode('utf-8').decode('unicode_escape')
        word_dict[keys[i]] = values[i]
    # print(word_dict)
    return word_dict


dict = get_dict()


def char_decode(str):
    while ('&#' in str):
        tmp = str.find('&#')
        str = str.replace('&#', '0', 1)
        key = str[tmp:tmp + 6]
        value = dict[key]
        str = str.replace(key, value, 1)
    # print(str)
    return str


url_head = "https://www.shixiseng.com/interns?page="
url_tail = "&type=intern&keyword=信息安全&area&months&days&degree&official&enterprise&salary=-0&publishTime&sortType&city=全国&internExtend"

for i in range(28):
    url = url_head + str(i) + url_tail
    resp = requests.get(url)
    """
    岗位: xxx
    公司: xxx
    薪资: xxx
    地区: xxx
    工作时间: xxx
    实习时长: xxx
    公司信息: xxx
    截至日期: xxx
    """

    data = resp.text
    f = open("info.md", "a+", encoding='utf-8')

    obj = re.compile(
        r'<p data-v-7c5681ee><a href="(?P<link>.*?)" title=.*?class="title ellipsis font" data-v-7c5681ee>(?P<post>.*?)</a>.*?day font" data-v-7c5681ee>(?P<salary>.*?)</span>.*?city ellipsis" data-v-7c5681ee>(?P<location>.*?)</span>.*?font" data-v-7c5681ee>(?P<worktime>.*?)</span>.*?font" data-v-7c5681ee>(?P<workdays>.*?)</span>.*?data-v-7c5681ee><a title="(?P<company>.*?)" href.*?"font" data-v-7c5681ee>(?P<info>.*?)</span>',
        re.S)
    obj2 = re.compile(
        r'<div class="cutom_font" data-v-6d86e756>截止日期:(?P<deadline>.*?)</div>',
        re.S)

    result = obj.finditer(data)
    for item in result:
        link = item.group("link")
        company = item.group("company")
        f.write("公司: " + company + '\n')
        # print("公司: " + company)
        salary = item.group("salary")
        f.write("薪资: " + char_decode(salary) + '\n')
        # print("薪资: " + char_decode(salary))
        post = item.group("post")
        f.write("岗位: " + '[' + char_decode(post) + '](' + link + ')' + '\n')
        # print("岗位: " + char_decode(post))
        location = item.group("location")
        f.write("地区: " + location + '\n')
        # print("地区: " + location)
        worktime = item.group("worktime")
        f.write("工作时间: " + char_decode(worktime) + '\n')
        # print("工作时间: " + char_decode(worktime))
        workdays = item.group("workdays")
        f.write("实习时长: " + char_decode(workdays) + '\n')
        # print("实习时长: " + char_decode(workdays))
        info = item.group("info")
        f.write("公司信息: " + char_decode(info) + '\n')
        # print("公司信息: " + char_decode(info))
        # 下一个网页提取开始
        url2 = link
        resp2 = requests.get(url2)
        result2 = obj2.finditer(resp2.text)
        for item2 in result2:
            deadline = item2.group("deadline")
        f.write("截至日期: " + deadline + '\n')
        # print("截至日期: " + deadline)
        # 下一个网页提取结束
        f.write('\n\n\n')
        # print()

f.close()
resp.close()
print("实习僧--信息安全实习岗位信息收集完毕")

爬取结果如下:

实习僧--信息安全实习岗位

收集涂鸦王国--精选作品

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
"""
爬取涂鸦王国--精选作品
1. 找到目标图片所在的父结点的属性 class="col-6 col-lg-3 mb-4"
2. 创建文件夹,此文件夹将存储爬取的图片
3. 继续查找图片 url 的属性 class="d-flex setgray" 和图片名字的属性 class="pt-2 font-weight-bold font-13 text-truncate pb-2"
4. 请求图片的 url,将返回结果以二进制的方式存储为图片并命名,放至文件夹中

PS: 相比于正则 re,bs4 更擅长处理非格式化的 HTML 源代码
PS: 浏览器显示源代码与爬取的源代码存在不一致的情况,以爬取的源代码为准
PS: 国外的插画网站不容易连接,需要手动下载源码,且仅支持不需要翻页的网页,因此不予演示
"""

from bs4 import BeautifulSoup
import requests
import re
import os

url = "https://www.gracg.com/works/best.more?type=jingxuan"

resp = requests.get(url)
html = resp.text
page = BeautifulSoup(html, "html.parser")
# print(page)
paints = page.find_all("div", attrs={"class": "col-6 col-lg-3 mb-4"})

os.makedirs("涂鸦王国")

for paint in paints:
    data = paint.find("a", attrs={"class": "d-flex setgray"})
    result = data.get("style")
    img_url = re.search(r"background:url\((?P<url>.*?)\?", result)
    url = img_url.group("url")
    # print(url)
    img_resp = requests.get(url)
    data2 = paint.find("div", attrs={"class": "pt-2 font-weight-bold font-13 text-truncate pb-2"})
    name = data2.text
    # print(name)
    with open(f"涂鸦王国/{name}.jpg", mode="wb") as f:
        f.write(img_resp.content)

f.close()
resp.close()
print("涂鸦王国--精选作品收集完毕")

爬取结果如下:

涂鸦王国--精选作品

获取猪八戒--python外包公司信息

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
"""
爬取猪八戒--python外包公司信息

1. 将目标网页源代码存储至 reference.html 并格式化
2. 使用 F12 查看目标网页模块源代码,找到标签 search-result-list-service
3. 打开 reference.html,删除该标签以外的全部无用模块,因为仅需要考虑该模块的内部内容
4. 找到公司名称、标题、价格、好评这四个对应的标签路径
5. 利用 xpath 获取目标公司信息

PS: xpath 匹配的索引是从 1 开始
PS: 当匹配目标属性值中含有空格或横杠 [' ' or '-'],那么最好换另一种匹配方法
"""

from lxml import etree
import requests

url = "https://zhuhai.zbj.com/search/service?l=0&kw=python&r=1"

resp = requests.get(url)
html = resp.text

"""
# 保存至本地
f = open("reference.html", mode="w", encoding='utf-8')
f.write(html)
"""

et = etree.HTML(html)
divs = et.xpath("//div[@class='search-result-list-service']/div")

for div in divs:
    company = div.xpath(
        "./div[2]/a/div[2]/div[1]/div[1]/text()")[0].strip().replace('\n', '')
    # print(company)
    title = div.xpath("./div[2]/a/text()")[0].strip().replace('\n', '')
    # print(title)
    price = div.xpath("./*/div[@class='price']/span/text()")[0]
    # print(price)
    comment = div.xpath("./*/div[@class='price']/div/span[2]/text()")[0]
    # print(comment)
    infomation = " ".join(["公司名:", company, "标题:", title, "价格:", price, "好评:", comment])
    print(infomation)
print("收集猪八戒--python外包公司信息完毕")

爬取微博视频--某博主的视频(使用代理池)

参考文章:Python学习笔记:requests请求传递Query String Parameters参数及提交From Data数据
参考视频:【python爬虫】爬取微博宅舞区视频,看的我心旷神怡吖~

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
"""
爬取微博视频--某博主的视频

1. 进入博主视频页,找到包含视频列表的包 getWaterFallContent?uid=xxx&&cursor=0,使用 Postman 测试可以正常响应数据
2. 记录该包每个视频对应的 oid,并点击进入第一个视频,发现视频网址的格式为 https://weibo.com/tv/show/{oid}?from=old_pc_videoshow
3. 找到包含可下载视频信息的包(包含 mp4 格式的视频)component?page=%2Ftv%2Fshow%2Fxxx%3Axxx,使用 Postman 测试不能正常响应数据
4. 经过测试发现请求头需要携带 cookie 和 referer(后者为防盗链,原理自行百度),之后进行常规操作:写代码
5. 使用代理池(可忽略)

PS: 使用 Postman 的目的是查看请求包是否能单独请求,如果不能,则可能是需要携带参数(如 referer)
PS: 稍微做个记录,便于以后再用(其中 {temp} 代表随机字符串)

- 微博视频网址(有多种)
https://weibo.com/tv/show/1034:{temp1}?mid={temp2}
https://weibo.com/tv/show/{temp1}:{temp2}?from=old_pc_videoshow
- 微博视频的抓包名
component?page=%2Ftv%2Fshow%2F{temp1}%3A{temp2}
- 上面抓到包其实有多个重名的,其中所包含的信息也不同
分别含有视频信息、弹幕信息、评论信息、推荐列表信息等
- 微博视频的请求网址
https://weibo.com/tv/api/component?page=%2Ftv%2Fshow%2F{temp1}%3A{temp2}
- 可以下载的视频链接(有多种,位于响应包 Video[data][Component_Play_Playinfo][urls])
高清 1080P: "//live.video.weibocdn.com/{temp1}.m3u8?{temp2}&ssig={temp3}&KID=unistore,video"
高清 1080P: "//f.video.weibocdn.com/o0/{temp1}.mp4?{temp2}&ssig={temp3}&KID=unistore,video"
- 爬取视频的流程
1. 推荐视频首页 / 博主视频页 -> 记录视频网址列表
2. 进入其中一个视频网址 -> 记录请求网址、视频下载链接、防盗链
3. 爬取全部视频

PS: 观察了多个微博视频不同的网址,有了如下发现

- 在推荐视频首页(https://weibo.com/tv/home)
热门视频有 3 个,推荐视频默认 9 个,如果往下刷新,响应包会继续更新
每个视频对应的网址位于响应包 Video[data][Component_Channel_Menu][list],包含 media_id、oid 和 mid

- 在博主的视频页(https://weibo.com/u/xxx?tabtype=newVideo)
默认视频有 20 个,同样的,如果往下刷新,响应包页会继续更新
每个视频对应的网址位于响应包 [list][data][num(视频列表)][url_struct][0][actionlog][oid],包含 oid

- 不同的视频类型
只有明星的视频下载网址才是 m3u8,普通用户或大 V 的视频下载网址是 mp4
理论上前者的视频格式播放速度是远快于后者,且占用资源更多(原因自行百度),缘由应该是粉丝访问基数太大
"""

import requests

def get_ip():
    # 反复提取代理 ip
    while 1:
        # 快代理的 ip 池
        url = "https://ent.kdlapi.com/api/getproxy/xxx"
        resp = requests.get(url)
        ips = resp.json()
        if ips['code'] == 0:
            for ip in ips['data']['proxy_list']:  # 拿到每一个 ip
                print("正在使用的代理ip:", ip)
                yield ip  # 一个一个返回代理 ip
            print("所有 ip 已经用完, 即将更新!")  # for 循环结束,继续提取新 ip
        else:
            print("获取代理 ip 出现异常,重新获取!")

def spider():
    VideoListURL = "https://weibo.com/ajax/profile/getWaterFallContent?uid=7417986528&cursor=0"
    _VideoURL = "https://weibo.com/tv/api/component?page=%2Ftv%2Fshow%2F1034%3A"
    while 1:
        try:
            proxy_ip = next(gen)  # 拿到代理 ip
            proxies = {"http": proxy_ip}
            headers = {
                "cookie":
                "XSRF-TOKEN=8-qZNWdSbKsiamPHyozxqwFW; UPSTREAM-V-WEIBO-COM=b09171a17b2b5a470c42e2f713edace0; _s_tentry=-; Apache=1355041230414.402.1655483749477; SINAGLOBAL=1355041230414.402.1655483749477; ULV=1655483749610:1:1:1:1355041230414.402.1655483749477:; SSOLoginState=1656495744; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WW5nJX_-MQO7xqQqvM-Xceq5JpX5KMhUgL.Foq41h5R1hnpShn2dJLoIp7LxKML1KBLBKnLxKqL1hnLBoMc1Kn71hnReKBR; ALF=1689218329; SCF=Aou9Itrp6glWp11idjzzspo8N_wqfHsFQqqa1JA9eOhGYlOaa7PLN30ZKWJ-k3JL_VNVOVU9ZSZeF5Y_nnzfv_c.; SUB=_2A25PyknLDeRhGeBH41IZ-CbNzzSIHXVsvjwDrDV8PUNbmtANLWqmkW9NQbiusC0nt6udPV9Dy81zsyo3G8u_G81J; UOR=,,www.qishe.org; WBPSESS=gvuJu6QavEC3mI3rC_-E-YqpQjRVYdjo2ix520eibeabVoMSe9WxqEZdwePTINaLrYyCDZZfNFb3HMiFIAnnYKvITw8-dTMIVBLvs80ukOewNoPSYWzCegUQvNl2vhBIh9RORAsi8a_LP_XwI3XowA==; PC_TOKEN=c24052de70"
            }
            resp = requests.get(VideoListURL, proxies=proxies, headers=headers)
            resp.encoding = "utf-8"
            VideoListJson = resp.json()['data']['list']
            # 此包一次存储 20 个视频,如需要抓取剩下的包,请自行修改
            count = 1
            for VideoJson in VideoListJson:
                oid = VideoJson['url_struct'][0]['actionlog']['oid']
                _oid = oid.split(':')[1]
                VideoURL = _VideoURL + _oid
                # print(VideoURL)
                headers = {
                    "cookie":
                    "XSRF-TOKEN=8-qZNWdSbKsiamPHyozxqwFW; UPSTREAM-V-WEIBO-COM=b09171a17b2b5a470c42e2f713edace0; _s_tentry=-; Apache=1355041230414.402.1655483749477; SINAGLOBAL=1355041230414.402.1655483749477; ULV=1655483749610:1:1:1:1355041230414.402.1655483749477:; SSOLoginState=1656495744; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WW5nJX_-MQO7xqQqvM-Xceq5JpX5KMhUgL.Foq41h5R1hnpShn2dJLoIp7LxKML1KBLBKnLxKqL1hnLBoMc1Kn71hnReKBR; ALF=1689218329; SCF=Aou9Itrp6glWp11idjzzspo8N_wqfHsFQqqa1JA9eOhGYlOaa7PLN30ZKWJ-k3JL_VNVOVU9ZSZeF5Y_nnzfv_c.; SUB=_2A25PyknLDeRhGeBH41IZ-CbNzzSIHXVsvjwDrDV8PUNbmtANLWqmkW9NQbiusC0nt6udPV9Dy81zsyo3G8u_G81J; UOR=,,www.qishe.org; WBPSESS=gvuJu6QavEC3mI3rC_-E-YqpQjRVYdjo2ix520eibeabVoMSe9WxqEZdwePTINaLrYyCDZZfNFb3HMiFIAnnYKvITw8-dTMIVBLvs80ukOewNoPSYWzCegUQvNl2vhBIh9RORAsi8a_LP_XwI3XowA==; PC_TOKEN=c24052de70",
                    "referer":
                    f"https://weibo.com/tv/show/{oid}?from=old_pc_videoshow"
                }
                params = {"page": f"/tv/show/{oid}"}
                # 下面这个 data 里面还包含 data 我是没想得到的,成功耗费了我两个小时 debug,充分的说明了该程序员的开发能力不足
                data = {
                    'data': '{"Component_Play_Playinfo":{"oid":"' + oid + '"}}'
                }
                resp2 = requests.post(VideoURL, proxies=proxies, headers=headers, params=params, data=data)
                resp2.encoding = "utf-8"
                Video = resp2.json()['data']['Component_Play_Playinfo']['urls']['高清 1080P']
                # 可在线播放的视频地址,也是我要下载的地址
                Video = "https:" + Video
                # print(Video)
                with open(f"{count}.mp4", mode="wb") as f:
                    f.write(requests.get(Video).content)
                count += 1
            print("获取微博用户的视频成功")
            return None  # 运行成功后,强制返回
        except:
            print("报错了")

if __name__ == '__main__':
    gen = get_ip()  # 代理 ip 的生成器
    spider()
image.png

爬取电影 emmm

实现自动化登入极验 / B 站 / 12306(绕过验证码)

推荐好文:利用selenium携带cookies实现免登录【可实现 selenium + cookies 的效果】

"""
实现自动化登入极验(Requests + 识别图片)
"""

"""
实现自动化登入 B 站(Selenium + 识别图片)
"""

"""
实现自动化登入 12306(Selenium + 拖动滑块)
"""
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐