声明:网站根目录下的robots.txt一般写了爬虫的协议,请遵守道德,不要乱爬,出了事别说是我教的。
基础知识部分
一、三国演义下载(request)
import requests
url = "http://10.163.72.39:7777/image/sanguo1.md"
res = requests.get(url)
print(res.status_code) #打印对象的响应状态码,以检查请求是否成功
print(res.text) #把对象的文本以字符串的形式返回
# 创建一个名为三国演义的txt文档,以写模式打开
file = open("三国演义.txt","w")
# 写进文件中,相当于—— 蔡徐坤.吃饭("包子")
file.write(res.text)
# 关闭文档,相当于—— 蔡徐坤.睡觉()
file.close()
测验:批量爬取三国演义前三章,分别为sanguo2.md和sanguo3.md
二、爬取一张图片(request)
import requests
url = 'http://10.163.72.39/img/angry.55b2c9de.gif'
res = requests.get(url)
print(res.status_code) #打印对象的响应状态码,以检查请求是否成功
print(res.content) #打印对象的二进制编码内容
# 新建了一个文件angry.jpg,这里的文件没加路径,它会被保存在程序运行的当前目录下。
# 图片内容需要以二进制wb读写。
photo = open('angry.jpg','wb')
# 获取pic的二进制内容
photo.write(res.content)
# 关闭文件
photo.close()
练习:我网站的所有图片,自己爬着玩吧
测验:天堂图片网批量爬取,任务要求,批量爬取从高渐离到孙悟空的十几张图片,其中有一张图片被我删除了,在爬取的时候请跳过。
三、爬取一段视频(request)
import requests
url = 'http://10.163.72.39/media/banner3.043818a0.mp4'
res = requests.get(url)
print(res.status_code) #打印对象的响应状态码,以检查请求是否成功
print(res.content) #打印对象的二进制编码内容
# 新建了一个文件banner.mp4,这里的文件没加路径,它会被保存在程序运行的当前目录下。
# 图片内容需要以二进制wb读写。
video = open('banner.mp4','wb')
# 获取pic的二进制内容
video.write(res.content)
# 关闭文件
video.close()
四、豆瓣电影top250爬虫(静态网页bs4)
http://10.163.72.39/%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1%20Top%20250.html
import requests,openpyxl
from bs4 import BeautifulSoup
wb=openpyxl.Workbook()
sheet=wb.active
sheet.title='豆瓣'
sheet['A1']='电影名'
sheet['B1']='评分'
sheet['C1']='推荐语'
sheet['D1']='链接'
for i in range(10):
url='http://10.163.72.39/%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1%20Top%20250.html?start='+str(i)+'&filter='
# url='https://movie.douban.com/top250?start='+str(i)+'&filter='
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
res=requests.get(url,headers=headers)
soup=BeautifulSoup(res.text,'html.parser')
movies=soup.find_all(class_="info")
for movie in movies:
href=movie.find('a')['href']
name=movie.find(class_="title").text
star=movie.find(class_="rating_num").text
quote=movie.find(class_="quote").text
sheet.append([name,star,quote,href])
print(href+name+star+quote)
wb.save('.\豆瓣爬虫的数据.xlsx')
五、机房管理系统爬虫(静态网页bs4)
爬取教师姓名的缩写,你们懂的,这个姓名缩写同时也是ftp的账号,可以用来爆破ftp的密码。
import requests,re
from bs4 import BeautifulSoup
txt=open('./teacher_name.txt','a')
url='http://10.163.72.11/index/admin/teacher'
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
res=requests.get(url,headers=headers)
soup=BeautifulSoup(res.text,'html.parser')
items = soup.find_all('h5',class_='card-title')
for item in items:
pattern = re.compile(r'【(.*?)】')
name = re.findall(pattern,item.text)[0]
print(name)
txt.write(name + 'down' + '\n')
txt.close()
六、爬取神秘暗网留言板(动态网站json)
import requests,openpyxl
wb = openpyxl.Workbook()
sheet = wb.active
sheet.title = '留言数据'
sheet['A1'] = '用户ID'
sheet['B1'] = '用户名'
sheet['C1'] = '积分'
sheet['D1'] = '留言内容'
# 爬取前十页
for i in range(1,10):
url = 'http://10.163.72.55/messageData.php?currentPage='+str(i)
res = requests.get(url)
res_jons = res.json() # 解析为json格式数据
print(type(res_jons))
massage_list = res_jons['data']
for item in massage_list:
id = item['id']
username = item['username']
rankScore = item['rankScore']
message = item['message']
sheet.append([id,username,rankScore,message])
wb.save('.\神秘暗网留言板爬虫.xlsx')
七、带着参数请求数据(偷看隐藏数据)
假设神秘暗网首页作业栏目,不可以点击查看更多,可以携带参数查看隐藏信息。
import requests
url = 'http://10.163.72.55/taskListData.php'
params = {'task_num':3}
res = requests.get(url,params=params)
res_json = res.json()
task_list = res_json['data']
for task in task_list:
print('作业标题为:',task['title'])
假设用户管理中,教师组属于敏感信息,不让普通用户查询,你知道该怎么做了吧。
import requests
url = 'http://10.163.72.55/userAdminDataClass.php'
params = {'className':'22计2'}
res = requests.get(url,params=params)
res_json = res.json()
user_list = res_json['data']
for user in user_list:
print('用户姓名为:',user['username'])
八、指挥浏览器登录神秘暗网(自动脚本)
from selenium import webdriver # 从selenium库中调用webdriver模块
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import time
# chrome_options = Options()
# chrome_options.add_argument('--no-sandbox') # 可选项,用于在 Linux 上启动 Chrome
# chrome_options.add_argument('--disable-dev-shm-usage') # 可选项,用于在 Linux 上启动 Chrome
# chrome_options.add_argument('--headless') # 可选项,无头模式
# chrome_options.add_argument('--disable-gpu') # 可选项,禁用 GPU
# driver = webdriver.Chrome(options=chrome_options)
driver=webdriver.Chrome()
driver.get('http://10.163.72.55/#/index/IndexTask') # 访问页面
time.sleep(2) # 暂停两秒,等待浏览器缓冲
login = driver.find_element(By.ID,'login')
login.click() # 点击【提交】按钮
username = driver.find_element(By.ID,'username') # 找到用户名输入框位置
username.send_keys('你的名字') # 输入文字
password = driver.find_element(By.ID,'password') # 找到密码输入框位置
password.send_keys(123456)
login_button = driver.find_element(By.CLASS_NAME,'login_button') # 找到密码输入框位置
login_button.click()
九、通过cookie留言(突破留言板限制)
import requests
#获得cookies
url='http://10.163.72.55/LoginPost.php'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'}
data={
'username': 'username',
'password': 'password',
}
login=requests.post(url,headers=headers,data=data)
cookies=login.cookies
print(cookies)
#用cookies登陆
url_2='http://10.163.72.55/messagePost.php'
params = {'gb_word':'没想到吧,我还是可以留言,哈哈'}
res=requests.get(url_2,cookies=cookies,headers=headers,params=params)
res_json = res.json()
print(res_json)
十、使用scrpit框架爬豆瓣
pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple/ # 安装环境
scrapy startproject douban # 创建项目
scrapy crawl douban #运行工程
爬虫模块(在spiders目录下新建xx.py文件)
# (爬虫)部门是公司的核心业务部门
# 负责创建requests对象和接受引擎发送过来的response(Downloader部门爬取到的内容),从中解析并提取出有用的数据。
# 它对应的是爬虫流程【解析数据】和【提取数据】这两步
import scrapy
import bs4
# 需要引用DoubanItem,它在items里面。因为是items在top250.py的上一级目录,所以要用..items,这是一个固定用法。
from ..items import DoubanItem
# DoubanSpider类继承自scrapy.Spider类
class DoubanSpider(scrapy.Spider):
name = 'douban' # 定义爬虫的名字,这个名字是爬虫的唯一标识
# allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。
# 如果网址的域名不在这个列表里,就会被过滤掉
# 一定在book.douban.com这个域名之下,防止爬到广告页面去
allowed_domains = ['book.douban.com']
# 定义起始网址,就是爬虫从哪个网址开始抓取
# 注:allowed_domains的设定对start_urls里的网址不会有影响
start_urls = ['https://book.douban.com/top250?start=0']
# 根据url的规律,构建出前三页地址
start_urls = []
for x in range(3):
url = 'https://book.douban.com/top250?start=' + str(x * 25)
start_urls.append(url)
# 解析下载器传过来的数据
def parse(self, response):
# 爬取的数据存储在response.text
bs = bs4.BeautifulSoup(response.text,'html.parser')
datas = bs.find_all('tr',class_="item")
for data in datas:
#实例化DoubanItem类。
item = DoubanItem()
# 书名
item['title'] = data.find_all('a')[1]['title']
#提取出出版信息,并把这个数据放回DoubanItem类的publish里。
item['publish'] = data.find('p',class_='pl').text
# 评分
item['score'] = data.find('span',class_='rating_nums').text
print(item['title'])
#yield item是把获得的item传递给引擎。
#有点类似return,不过它和return不同的点在于,它不会结束函数,且能多次返回信息
yield item
数据处理模块(items.py)
# (数据管道)部门则是公司的数据部门
# 只负责存储和处理Spiders部门提取到的有用数据。这个对应的是爬虫流程【存储数据】这一步。
import scrapy
#定义一个类DoubanItem,它继承自scrapy.Item
class DoubanItem(scrapy.Item):
# scrapy.Field() 相当于自定义字典类型
title = scrapy.Field() #定义书名的数据属性
publish = scrapy.Field() #定义出版信息的数据属性
score = scrapy.Field() #定义评分的数据属性
设置(settings.py)
# 保存爬取的数据
FEED_URI='./storage/data/%(name)s.csv'
FEED_FORMAT='csv'
FEED_EXPORT_ENCODING='ansi' # 导出文件编码,ansi是一种在windows上的编码格式
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 是否需要遵守爬虫规则,改成不遵守
ROBOTSTXT_OBEY = False
# 爬虫的速度
DOWNLOAD_DELAY = 0.5
主程序启动模块 (main.py,和scrapy.cfg同级)(注意:一定要将项目文件夹作为编程文件夹)
#导入cmdline模块,可以实现控制终端命令行。
from scrapy import cmdline
#用execute()方法,输入运行scrapy的命令。
cmdline.execute(['scrapy','crawl','douban'])
作业:爬取当当网前三页,书名,作者,价格
http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-year-2018-0-1-1
扩展提升
爬取每一条新闻里的内容
http://www.news.zjut.edu.cn/5415/list.htm
# (爬虫)部门是公司的核心业务部门
# 负责创建requests对象和接受引擎发送过来的response(Downloader部门爬取到的内容),从中解析并提取出有用的数据。
# 它对应的是爬虫流程【解析数据】和【提取数据】这两步
import scrapy
import bs4
# 需要引用DoubanItem,它在items里面。因为是items在top250.py的上一级目录,所以要用..items,这是一个固定用法。
from ..items import DoubanItem
# DoubanSpider类继承自scrapy.Spider类
class DoubanSpider(scrapy.Spider):
name = 'douban' # 定义爬虫的名字,这个名字是爬虫的唯一标识
# allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。
# 如果网址的域名不在这个列表里,就会被过滤掉
# 一定在book.douban.com这个域名之下,防止爬到广告页面去
allowed_domains = ['www.news.zjut.edu.cn']
# 定义起始网址,就是爬虫从哪个网址开始抓取
# 注:allowed_domains的设定对start_urls里的网址不会有影响
start_urls = ['http://www.news.zjut.edu.cn/5415/list.htm']
# 解析下载器传过来的数据
def parse(self, response):
# 爬取的数据存储在response.text
bs = bs4.BeautifulSoup(response.text,'html.parser')
datas = bs.find_all('span',class_="news_title")
for data in datas:
href = data.find('a')['href']
link = 'http://www.news.zjut.edu.cn/5415/list.htm' + href
# 链接先爬下来回传给引擎,引擎通过调度器给下载器,下载好了再传给我
yield scrapy.Request(link, callback=self.parse2)
#这个就是下载器下载好的数据
def parse2(self, response):
bs = bs4.BeautifulSoup(response.text,'html.parser')
item = DoubanItem()
item['title'] = bs.find(class_='arti_title').text
yield item
十一、破解并下载视频流
import requests,re,random
from Crypto.Cipher import AES
# 伪装请求头
user_agent = [
'Mozilla/5.0 (Windows NT 5.2) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30',
'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C)',
'Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.9.168 Version/11.50',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C)',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
]
headers = {'User-Agent': random.choice(user_agent)}
url = 'http://www.nvic.edu.cn/CompetitionVideo/Detail?worksId=3ddcd2d0-39f1-49b8-83a2-03b8e5ef780d&sType=5&competitionId=ce116ee4-ca64-4c16-9aff-750fed3335cf'
res = requests.get(url,headers=headers)
# 获取几个独立视频的链接
pattern=re.compile('data-path="(.*?)"')
indexs_list=re.findall(pattern,res.text)
for index in indexs_list:
# 获取视频文件存放路径
path = index[:-10]
res = requests.get(index,headers=headers)
pattern=re.compile('URI="(.*?.key)"')
key= re.findall(pattern,res.text)[0]
key_url = path + key # 拼凑出key的地址
print(key_url)
key_res = requests.get(key_url) # 拿到key的内容
print('已获取到key')
print(key_res.content)
aes = AES.new(key_res.content, AES.MODE_CBC, b'0000000000000000') # 制作解密文件
print('已成功制作解密文件')
# 拿视频碎片
pattern=re.compile('(filesequence\d+.ts)')
filesequences_list=re.findall(pattern,res.text)
count = 1 # 计数、缓解等待压力
for filesequence in filesequences_list:
filesequence_url = path + filesequence
res = requests.get(filesequence_url,headers=headers)
# 图片内容需要以二进制wb读写。
video = open(f'{key}.mp4','ab+')
# 获取pic的二进制内容
video.write(aes.decrypt(res.content))
# 关闭文件
video.close()
count += 1
print("\r[下载进度]:{}{:.2f}%".format('>'*count,count/len(filesequences_list)*100),end='')
十二、新遇到的一点反爬问题
最近爬这个网站遇到一点问题,https://www.ly.com/hotel/hotellist?pageSize=20&t=1693794571107&city=321&inDate=2023-09-04&outDate=2023-09-05&filterList=8888_1
以前可以爬,现在不能爬,经过研究,发现是网站开发者增加了对请求头字段的校验。
import requests
headers_str = '''accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
accept-language: zh-cn
appfrom: 16
cluster: idc
Connection: keep-alive
Cookie: soso_17u_tab_open_index=1; H5CookieId=2a31035b-81b0-452f-8af5-4bc2cb6d6229; firsttime=1693790207090; abtkey=037eed29-b152-4fc3-92a8-027faa2dffc6; _tcudid_v2=GVAglBHWXx1wFDh4_P4gvwe79p_DO7Vf2Yj7sQ9vCd4; nus=userid=682242716&nickName=%e5%90%8c%e7%a8%8b%e4%bc%9a%e5%91%98_0D043E7512A&level=1; __tctma=144323752.1693790169808694.1693790169437.1693790169437.1693793067529.2; hotel_lang=zh-cn; 17uCNRefId=RefId=0&SEFrom=&SEKeyWords=; TicketSEInfo=RefId=0&SEFrom=&SEKeyWords=; CNSEInfo=RefId=0&tcbdkeyid=&SEFrom=&SEKeyWords=&RefUrl=; qdid=-9999; businessLine=hotel; H5Channel=mnoreferseo%2CSEO; indate=2023-09-09; outdate=2023-09-10; route=e83eaebd8f07fc1b8cfab528aeb2900e; lasttime=1694239332948; JSESSIONID=A23D8BD953AE131A1233B6F406759B2E
deviceid: 2a31035b-81b0-452f-8af5-4bc2cb6d6229
Host: www.ly.com
Referer: https://www.ly.com/hotel/hotellist?pageSize=20&t=1694239332807&city=321&inDate=2023-09-09&outDate=2023-09-10&filterList=8888_1
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
timezone: 8
tmapi-client: tpc
traceid: d6d36af2-7f3a-4504-a125-db1cfa470c97
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'''
headers_dict = {}
line_list = headers_str.split('\n')
for line in line_list:
key = line.split(':')[0]
value = line.split(':')[1]
headers_dict[key] = value.strip()
# print(headers_dict)
url = 'https://www.ly.com/tapi/v2/list?pageSize=20&t=1694239311116&city=321&inDate=2023-09-09&outDate=2023-09-10&filterList=8888_1&pageIndex=0&sugActInfo='
res = requests.get(url,headers=headers_dict)
res_json = res.json()
hotel_list = res_json['data']['hotelList']
for hotel in hotel_list:
hotelName = hotel['hotelName']
print(hotelName)
项目一:消息通知器
一、制作背景
如果要应聘某个单位,但是不知道这个单位什么时候发布招聘信息,总不能天天上官网去看吧,对于我这样孤僻的性格,消息闭塞,很有可能错过重要的招聘信息。
因此,我需要一个程序可以自动爬取网站的消息栏,如果发现有自己关注的信息,则发一封邮件给自己。
例如海盐商贸学校发布了一条招聘计算机教师的通知,我需要第一时间得到通知。
二、代码分享
import requests
import smtplib
import schedule
import time,os
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
from email.header import Header
def account_save(keyword,qqmail):
#----保存用户邮箱和关键词信息----#
with open(account_path,'w') as f:
f.writelines([keyword+'\n',qqmail])
f.close()
def account_load():
#----读取邮箱和关键词信息----#
with open(account_path,'r') as f:
f_content=f.readlines()
return f_content[0][:-1],f_content[1]
def YanGongBu_spider(keyword):
#----爬取研工部通知栏前三项----#
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url='http://yjsb.zjnu.edu.cn/'
res=requests.get(url,headers=headers)
soup=BeautifulSoup(res.text,'html.parser')
titles=soup.find_all('span',class_="meta-title")
for title in titles[10:13]:
if keyword in title.text:
send_email(title.text,qqmail)
def send_email(title,qqmail):
#----使用710464440代发邮件----#
account=qqmail
password='这里填写邮箱密码'
reveiver='710464440@qq.com'
mailhost='smtp.qq.com'
qqmail=smtplib.SMTP()
qqmail.connect(mailhost,25)
qqmail.login(account,password)
content=title
massage=MIMEText(content,"plain","utf-8")
subject='研工部通知'
massage['Subject']=Header(subject,'utf-8')
try:
qqmail.sendmail(account,reveiver,massage.as_string())
print('邮件发送成功')
except:
print('邮件发送失败')
qqmail.quit()
if __name__=='__main__':
base_dir = os.path.dirname(__file__) #获取当前文件夹的绝对路径
account_path=base_dir+"/account.txt"
print(account_path)
if not os.path.exists(account_path):
keyword=input('请输入你想关注的内容的关键词(例如:招聘):')
qqmail=input("请输入你的qq邮箱地址(例如:715555555@qq.com):")
account_save(keyword,qqmail)
else:
keyword,qqmail=account_load()
YanGongBu_spider(keyword)
input('按任意键退出程序')
#这段代码用于挂远程服务器
#schedule.every().day.at('17:30').do(YanGongBu_spider)
#while True:
#schedule.run_pending()
#time.sleep(1)
三、使用小tip
如果是本地使用的话,利用windows的任务计划程序,每天定时运行程序,如果那个时间电脑没开,程序则不会运行,而且如果在玩游戏,可能会被黑窗口弹一下,比较影响体验。
因此,我们需要将代码挂在远程的服务器上,服务器24小时运行,完美解决问题。
项目二:网课自动刷点赞刷评论刷积分
疫情期间上网课,学校使用UMN教学平台进行授课,点赞和评论都可以获得积分,积分影响最终成绩,别的同学都是手动弄,我觉得太麻烦,所以我打算用Python刷一刷。
#2.2版本公告:新增账号保存功能,用户只需要输入一次账号密码,会自动以文本格式保存在当前文件夹下,第二次运行会自动读取
#2.1版本公告:程序通过相对路径找到chromedriver.exe,不需要用户再手动填写绝对路径了
#2.0版本公告:加入自动评分和评论的功能,加入可显示剩余人数的功能
#1.7版本公告:做了代码优化,并封装了部分复用的代码
#1.6版本公告:加入了用户自定义输入,可自定义评论内容
#1.5版本公告:修复了因找不到chromedriver而造成的'chromedriver' executable needs to be in PATH的bug
#1.4版本公告:修复因跳过页面展开而造成的实际人数统计的错误,加入了页面滑动以及显性等待机制,最长等待20秒
#1.3版本公告:修复一处因服务器排队而造成的程序无法运行的bug,加入了3分钟的页面隐性等待
#1.2版本公告:修复一处在展开页面时,因为网络不稳定而造成的list index out of range的bug,加入了异常跳过机制
#1.1版本公告:修复一处因页面返回而导致的实际点赞人数不足的bug,在页面返回时需重新展开所有作业名单
#unm自动点赞器1.0功能介绍:用于在unm平台实现对其他同学作业的自动点赞。
import time,pyautogui,openpyxl,os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def look_all_task():
#----展开所有作业名单----#
try:
for i in range(2):
pyautogui.scroll(-10000)
more = WebDriverWait(driver,20).until(EC.presence_of_element_located((By.CLASS_NAME,"btn-inner")))
driver.execute_script("arguments[0].click();",more)
time.sleep(2)
except IndexError:
print('跳过因为网络不稳定展开页面失败而造成的list index out of range问题')
def account_save(user_acount,user_password):
#----保存用户账号密码信息----#
with open(account_path,'w') as f:
f.writelines([user_acount+'\n',user_password])
f.close()
def account_load():
#----读取用户账号密码信息----#
with open(account_path,'r') as f:
f_content=f.readlines()
return f_content[0],f_content[1]
if __name__=='__main__':
#----用户自定义输入----#
base_dir = os.path.dirname(__file__) #获取当前文件夹的绝对路径
account_path=base_dir+"//account.txt"
user_comment=input('请输入你要评论的内容,(样例:你的作业做得真好,非常优秀):')
if not os.path.exists(account_path):
user_acount=input('请输入你的umn账号:')
user_password=input('请输入你的umn密码:')
account_save(user_acount,user_password)
else:
user_acount,user_password=account_load()
#----登录网站----#
url_task='https://m.umu.cn/session/exercise/?surl=1SqbQ623d'
url='https://www.umu.cn/index#/index'
driver=webdriver.Chrome(executable_path='chromedriver.exe')
# driver=webdriver.Chrome()
driver.get(url)
driver.implicitly_wait(180) #隐式等待,最长等待180秒
account=driver.find_elements_by_class_name('input-text')
account[0].send_keys(user_acount)
account[1].send_keys(user_password)
button=driver.find_element_by_class_name('btn-warning')
button.click()
time.sleep(2)
#----转到作业二的界面----#
driver.get(url_task)
time.sleep(4)
look_all_task()
#----统计任务数----#
look_task=driver.find_elements_by_class_name('review-status')
surplus=len(look_task)
#----进入个人作业详情页----#
for j in range(50):
look_task=driver.find_elements_by_class_name('review-status')
driver.execute_script("arguments[0].click();",look_task[j+1])
time.sleep(4)
driver.implicitly_wait(10)
#----点赞----#
try:
like=driver.find_element_by_class_name('liked-user-prise')
driver.execute_script("arguments[0].click();",like)
print('点赞成功')
time.sleep(2)
except:
print('没有找到点赞功能')
#----评论打分----#
try:
comment_button = driver.find_element_by_class_name('do-score')
pyautogui.scroll(-1000)
time.sleep(2)
comment_button.click()
time.sleep(2)
score=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div/div/div/div[2]/div/div/div/div[2]/div[1]/div/input')
score.send_keys('100')
comment=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div/div/div/div[2]/div/div/div/div[3]/div/textarea')
comment.send_keys(user_comment)
time.sleep(1)
submit=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div/div/div/div[1]/div/span[2]/span')
submit.click()
print('评论成功')
time.sleep(2)
except:
print('读取标签失败')
surplus-=1
print('剩余',surplus)
#----转到作业二的界面并展开作业列表----#
driver.get(url_task)
time.sleep(2)
driver.implicitly_wait(10)
look_all_task()
总结:这种程序实际上是模仿浏览器进行操作,很难防范,可造成的危害也比较有限,纯属娱乐性质。
项目三:爬取umn网站的所有视频
一、网站分析
打开课程详情页,目标是爬取所有的教学视频。
在详情页抓包,可以得到前三个视频的链接后缀。
第一个视频:1581601804.0237.24958.6125399.mp4
第二个视频:1581605929.0875.63457.6129383.mp4
第三个视频:1581605996.445.72069.6126469.mp4
那这个后缀怎么得到呢,首页的源代码里面是没有的,只能抓包看看,果然发现一个很萌的东西,因为开发者为了让首页加载出封面的图片,而这个图片又是直接从视频截取的,然后顺理成章的,网站开发者为了图方便省事,直接就用了和视频一样的url,只是后缀换成了jpg而已。
既然这样就很简单了,渲染出整个页面的数据,然后取出视频的后缀,拼接一下就行了,代码如下。
二、完整代码
#2.1版本公告:从程序目录启动谷歌浏览器驱动
#2.0版本公告:下载内容从网站动态获得
#1.3版本公告:显示已找到多少个资源
#1.2版本公告:加入了文本进度条显示
#1.1版本公告:新增自动创建文件夹功能,文件检索功能,文件已存在时不会重复下载
#umn一键视频爬取器1.0版本介绍:用于爬取umn教学平台上的的教学视频
import time
import pyautogui
import re
import requests
import os
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def video_url_get(url_course):
#----获取视频的url----#
video_list=[]
#----设置浏览器静默模式(已停用,否则无法下滑鼠标)----#
chrome_options=Options()
chrome_options.add_argument('--headless')
diver=webdriver.Chrome(executable_path='chromedriver.exe')
#----访问到首页----#
diver.get(url_course)
time.sleep(4)
#----鼠标往下滑两次----#
for i in range(5):
pyautogui.scroll(-10000)
time.sleep(2)
#----获取整个页面的数据,提取出视频后缀----#
Pagesource=diver.page_source
video_tails=re.compile('(\d*\.\d*\.\d*.{0,10}).mp4',re.S).findall(Pagesource)
diver.close()
for video_tail in video_tails:
video_url='https://statics0.umustatic.cn/videoweike/teacher/weike/4kXW2806/transcoding/'+video_tail+'.mp4'
video_list.append(video_url)
return video_list
def downloader(url):
#----下载器----#
start=time.time()
size=0 #定义已下载文件的大小(byte)
chunk_size=1024 #定义每次下载的数据大小(byte)
root='d://umn_spider_video//'
path=root+url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
res=requests.get(url,stream=True)
content_size=int(res.headers['content-length'])
if res.status_code==200:
print('[文件大小]:%0.2f MB'%(content_size/1024/1024)) #将byte换算成MB
print("急速爬虫器正在疯狂下载!!!".center(50,'-'))
with open(path,'wb') as f:
for data in res.iter_content(chunk_size=chunk_size):
f.write(data)
size+=len(data)
print("\r[下载进度]:{}{:.2f}%".format('>'*int(size*50/content_size),size*100/content_size),end='')
print('\n下载成功,文件自动帮您保存在d:/umn_spider_video/')
else:
print('文件已存在')
except:
print('爬取失败')
if __name__=='__main__':
url_course=input('请输入课程首页的网址,如果不清楚请看教程:')
# url_course='https://m.umu.cn/course/?groupId=4138993&sKey=0e6490a0d5ef477593326d2e8cd53faa&from_type=myparticipate'#专业教学设计与案例分析
# url_course='https://m.umu.cn/course/?groupId=5001078&sKey=e30c05f1c34302d77478bf49a21daec2&from_type=myparticipate' #职业教育德育研究
video_list=video_url_get(url_course)
print('已找到资源共%d个'%len(video_list))
for url in video_list:
downloader(url)
input('任务全部完成,欢迎您的再次使用,按任意键退出。')
有了这个程序模板,只要把url_course换成你自己的课程url,就可以爬取到全部的视频,按理说应该可以爬取任意的课程视频了,我又用这个程序取爬取了另外一门课程的视频,实测是没问题的。
就是注意一点,如果用于盈利的话,就涉及侵权,侵权违法,不要说是我教的。
项目四:网易云歌曲爬虫
import random,re,os,time
import requests
def downloader(url,name):
#----下载器----#
size=0 #定义已下载文件的大小(byte)
chunk_size=1024 #定义每次下载的数据大小(byte)
root='./蔡徐坤动听音乐/'
path=root+ name + '.mp3'
try:
# 如果文件夹不存在,则创建文件夹
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
res=requests.get(url,stream=True,headers=headers)
content_size=int(res.headers['content-length'])
if res.status_code==200:
print('[文件大小]:%0.2f MB'%(content_size/1024/1024)) #将byte换算成MB
print("利神超极速爬虫器正在疯狂下载!!!".center(50,'-'))
with open(path,'wb') as f:
for data in res.iter_content(chunk_size=chunk_size):
f.write(data)
size+=len(data)
print("\r[下载进度]:{}{:.2f}%".format('>'*int(size*50/content_size),size*100/content_size),end='')
print(f'\n下载成功,文件自动保存在当前目录{path}')
else:
print('文件已存在')
except:
print('爬取失败')
# 伪装请求头
user_agent = [
'Mozilla/5.0 (Windows NT 5.2) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30',
'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C)',
'Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.9.168 Version/11.50',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C)',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
]
headers = {'User-Agent': random.choice(user_agent)}
# 爬取歌手页
url = 'https://music.163.com/artist?id=12932368'
res=requests.get(url,headers=headers)
#用正则表达式提取id和歌曲名,<a href="/song?id=1360512113">记得</a>
pattern=re.compile('<a href="/song\?id=(\d+)">.*?</a>')
ids=re.findall(pattern,res.text)
pattern=re.compile('<a href="/song\?id=\d+">(.*?)</a>')
names=re.findall(pattern,res.text)
# 批量下载歌曲
for id,name in zip(ids,names):
url = f'https://music.163.com/song/media/outer/url?id={id}'
downloader(url,name)
# res=requests.get(url,headers=headers)
# file = open(f'{name}.mp3','wb')
# file.write(res.content)
# file.close()
input('爬虫完毕,不要问谁开发的,深藏功与名,按任意键退出')
项目五:有道词典接口爬虫
一、制作背景
新手玩家喜欢爬资源,中级玩家喜欢爬数据,高级玩家喜欢爬接口。
最近做了一个翻译接口,这下看不懂的英语可以直接翻译,无需外网,翻译几遍总能记住,这下总没借口了吧。
原理其实很简单,当然不是我的电脑放了一个本地词典,因为大家其实也发现了,这个是可以翻译句子的,而且支持几十种语言。🤠
实际上是通过破解有道词典的翻译接口,最终的翻译服务并不是我提供的,如果某一天接口不能用的,应该就是有道词典的加密系统维护升级了😅
别人的服务花了大力气做的接口,爬虫弄来放在自己的站点,如果用来盈利的话就违法了,不过我就是放在内网供班级使用,也不盈利,有道词典拿我也没辙。
二、接口调用
HTTP 方法:POST
请求URL:http://10.163.72.55:5000/todo1
URL参数:
data:需要翻译的内容
返回:
data{
content:翻译完成的内容
}
三、请求示例
1.Python
from requests import put, get
html=put('http://10.163.72.55:5000/todo1', data={'data': 'I am a student'}).json()
print (html)
2.PHP
<?php
$content = $_POST['content'];
// 解码,Unicode转义(\uXXXX)的编码和解码
function decodeUnicode($str)
{
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i',
create_function(
'$matches',
'return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");'
),
$str);
}
function curlrequest($url,$data,$method='post'){
$ch = curl_init(); //初始化CURL句柄
curl_setopt($ch, CURLOPT_URL, $url); //设置请求的URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //设为TRUE把curl_exec()结果转化为字串,而不是直接输出
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); //设置请求方式
curl_setopt($ch,CURLOPT_HTTPHEADER, array( "X-HTTP-Method-Override: $method")); //设置HTTP头信息
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //设置提交的字符串
$document = curl_exec($ch); //执行预定义的CURL
curl_close($ch);
return $document;
}
$url = 'http://10.163.72.55:5000/todo1';
$data = "data=$content";
$return = curlrequest($url, $data, 'put');
// ajax异步返回数据
$a = array();
$a['content'] = $return;
echo json_encode($a);
exit;
?>
四、制作前端窗口
教大家如何制作一个漂亮的前端窗口,既然是做盗版软件就做得像一点。
import requests
import json
from tkinter import Tk,Button,Entry,Label,Text,END
# 对利神翻译接口发起请求,获得数据
class LiShenFanYi(object):
def __init__(self):
pass
def crawl(self,word):
html = requests.put('http://10.163.72.55:5000/todo1', data={'data': word}).json()
return html
# 前段窗口应用程序
class Application(object):
def __init__(self):
self.window = Tk()
self.fanyi = LiShenFanYi()
self.window.title(u'我的翻译') # 设置标题
#设置窗口大小和位置
self.window.geometry('310x370+500+300')
self.window.minsize(310,370)
self.window.maxsize(310,370)
#创建一个文本框
#self.entry = Entry(self.window)
#self.entry.place(x=10,y=10,width=200,height=25)
#self.entry.bind("<Key-Return>",self.submit1)
self.result_text1 = Text(self.window,background = 'azure') # 设置背景颜色
self.result_text1.place(x = 10,y = 5,width = 285,height = 155)
self.result_text1.bind("<Key-Return>",self.submit1)
#创建一个按钮,并为按钮添加事件
self.submit_btn = Button(self.window,text=u'翻译',command=self.submit)
self.submit_btn.place(x=205,y=165,width=35,height=25)
self.submit_btn2 = Button(self.window,text=u'清空',command = self.clean)
self.submit_btn2.place(x=250,y=165,width=35,height=25)
#翻译结果标题
self.title_label = Label(self.window,text=u'翻译结果:')
self.title_label.place(x=10,y=165)
#翻译结果
self.result_text = Text(self.window,background = 'light cyan')
self.result_text.place(x = 10,y = 190,width = 285,height = 165)
# 回车翻译
def submit1(self,event):
#从输入框获取用户输入的值
content = self.result_text1.get(0.0,END).strip().replace("\n"," ")
#把这个值传送给服务器进行翻译
result = self.fanyi.crawl(content)
#将结果显示在窗口中的文本框中
self.result_text.delete(0.0,END)
self.result_text.insert(END,result)
#print(content)
def submit(self):
#从输入框获取用户输入的值
content = self.result_text1.get(0.0,END).strip().replace("\n"," ")
#把这个值传送给服务器进行翻译
result = self.fanyi.crawl(content)
#将结果显示在窗口中的文本框中
self.result_text.delete(0.0,END)
self.result_text.insert(END,result)
print(content)
#清空文本域中的内容
def clean(self):
self.result_text1.delete(0.0,END)
self.result_text.delete(0.0,END)
def run(self):
self.window.mainloop()
if __name__=="__main__":
app = Application()
app.run()