【Python】No.8网络爬虫基础-爬取课表为例
爬虫简介
当今是一个数据为王的时代,互联网存储了大量的信息。作为没有掌握一定爬虫技术的网民,我们可能都会通过浏览器来访问互联网上的内容。但如果我们想要批量获取一些分散在互联网各个角落的信息,手动获取这些信息可能会非常麻烦、耗费人力。因此,小编想跟大家分享一个系列:如何用它爬取一些数据,并将其转化为价值数据并进行线性回溯分析,具有一定的经济意义。
网络爬虫是一种按照一定规则自动从万维网上爬取信息的程序或脚本。
通过程序,我们模拟浏览器向服务器发送请求,获取信息,分析信息并存储我们需要的价值数据。
以百度新闻为例。出版商每天发布的新闻内容不同,但版式格式是相同的。为了方便每天重复的排版工作,发布者会用一些手段自动“补”这些内容,爬虫也会跟着补。爬取我们需要的内容的方法。
我们抓取的对象是HTML超文本标记语言,它是最基本的网页语言,而不是编程语言。
网页结构
网页结构也是一个非常层次化的结构,树形结构。访问网页远非输入地址并查看网页那么简单。我们需要在浏览器中按“F12”,或者右键单击网页并选择“”来查看网页背后的代码。
以谷歌浏览器为例,在百度新闻网站上,按“F12”,会出现浏览器检查窗口。默认窗口是当前界面的HTML代码。
网页是根据此源代码格式化的。点击上面的代码,就可以看到这些代码对应的内容在哪里。它们将内容存储在嵌套在每个 div 下的许多小列表中。
网页修改方法和选择器
-CSS 和选择器
处理都是为了装饰网页,比如第一行标签名的选择,red表示颜色以红色为主,div{}是它的命名格式。不同的选择器有不同的应用,也有各自的优缺点。这里我就不一一解释了,大家可以参考下面的网站。
新手教程:
这些选择器往往会不断发展,并且有很多扩展选择器。
通过这些选择器,我们可以爬取我们能看到的内容。没有显示的内容我们可能看不到,这为我们以后的分析奠定了基础。当我们的爬虫学习高级内容时,我们所有人都可以自动化我们的乱序课程。但是,如果该IP地址不断被访问,管理员就会发现并禁止您的IP地址。不过,我们也可以使用IP代理来抓取消息。总之,这些网页不断地与爬虫“战斗”(京东在这方面的限制不像淘宝那么严格,所以我们可以在京东做一些实验)。
爬虫需要安装的包
对于自动化网络爬虫来说,让机器自己模拟爬行需要下载和使用工具。
下面给大家分享一下如何下载并添加到环境变量中。
下载地址:
首先打开网址,一定要选择与您实际浏览器版本相同的下载。您可以先通过以下步骤检查自己的版本。
然后,下载完后,解压压缩文件得到.exe,然后打开本机中的高级设置,继续点击环境变量,复制.exe在本机上的地址,添加到环境变量中,然后确认。能。
提示:您需要知道 .exe 的位置。爬虫稍后需要使用这个地址。
图书馆基本介绍:
另外,我们日常爬虫中也可能用到的库
有兴趣的同学可以继续研究。
爬虫简介
导入必要的库
使用
上面的代码中,我们以编程方式访问百度网页,其中get方法中使用“.get(网页地址)”来访问网页。我们使用“=.get(url)”将获取到的信息传入。我们输出的不是网站代码,而是响应代码。
响应代码状态代表我们之前的结果。常见的是200,表示成功; 403,无权限访问; 404 文件不存在; 502、服务器访问错误。相信您以前在访问一些国外网站时可能经常遇到这些错误。
如果我们想看到之前使用“.get(url)”的网页内容,我们需要先执行“.='utf-8'”。这一步是将网页内容编码为utf-8,否则我们在网页中看不到中文。
完成此操作后,我们就可以看到网页的代码了。
相信大家对爬虫都有一个简单的了解。下面我们通过例子来了解一下操作过程。我们先从大家的问题——爬取南深教务在线的课程表开始。
爬虫教育与实战
访问网站
首先我们找到之前下载的文件夹位置(一定要解压,并将解压后的exe文件放在该文件下。小编一开始就是因为这个疏忽而报错的,希望大家不要踩这个陷阱再次),复制位置,会显示如下:
运行此代码即可自动进入教务在线课程表。需要注意的是,这个符号“\”前面需要加一个r。
获取班级所有内容
小编在这里简单阐述一下我们如何获取此类课表信息。我们选择不同的类,相当于不同的值,然后将它们从前端传输到后端,使用 if 语句向我们提供这些信息。所以我们想要得到这样的值,首先要得到这些类的列表,然后浏览器才能得到这些类表的内容。其实这些类的信息已经在前端显示出来了。我们只需要按下拉框就可以找到所有班级的信息。虽然我们肉眼可能看不到它,但它的本质已经储存在这个界面里了。我们可以通过按F12查看源代码来验证这一点。
我们可以发现这个信息就存储在body下面。您可以通过选择名称来找到这些信息(这些内容已加载到前端)。
所以我们首先需要定义一个名字,因为名字后面的值是随机的,需要手动导入,比较麻烦。然而,还有一些其他选择器可以自动处理它。这里我分享一下爬虫更高级的内容。我们需要选择其他选择器之一,称为上面的同级选择器方法,以准确定位我们需要抓取的内容。具体用法如下:
将此 ID 复制到“#Term+=”。通过运行此代码,您可以获得信息。这段代码如何运行?我们发现网页的代码接近id=Term,这样就可以连续两次找到我们需要的信息(因为小编发现学校的教务系统有爬虫措施,有些元素是动态变化的,但是兄弟选择器定位他们的标签,爬行能力好的人只要能正常打开网页就可以爬到自己想看的东西)。
但是这个显示和我们网页的显示是不一样的。这就是我们前面讲的html的结构。这个内容不能直接使用,所以我们需要将其转换为列表形式。这里用到了我们之前学过的容器列表list。我们首先需要分割这个列表,使用 \n-- 来表示换行符。要使用它,我们需要使用之前同学分享的split。
浏览器自动选择并点击
接下来我们将使用浏览器自动“查询”这个键,但是这个键在哪里呢?我们必须再次按F12才能找到span,这是一个触发浏览器应用程序的事件。我们必须找到触发span的代码。我们可以找到href=,(这是一种可以触发执行的前端语言,很大概率可以将查询定位到这个标签。
我们发送的这个span还有一个id“”并复制它。
然而,运行时出现错误,并且没有定义键,因此我们使用我们之前的包:来自 mon.keys 的键。这样我们就可以得到我们需要的课程内容了。接下来我们就来收集这些内容。这时候我们就需要对列表的结构有一定的了解,并进行梳理。
获取指定班级的课程表
我们继续F12找到课程内容的位置,并找到一个标签,然后再往下找到一个表格标签。打开tbody找到我们需要的内容。 tbody下面还有一个tr。单击即可找到它。这是一行一行的。上面的-color就是给它上色(类似的内容在前面的css文件中讨论过)。下一层结构中还有一个td。点击发现,这就是我们真正需要获取的内容。
每个 TR 中的布局都是相同的,第一个是班级,然后是课程、学分和班级地址。这就需要我们自己定义顺序。具体操作如下:
我们用soup将html从中分离出来(上一篇文章中已经引用了来自bs4的解析文件),然后用soup.选择我们需要的内容:
=汤。('.tr')[1:-1]
定义获取网页内容的函数
郑重声明:
爬虫本身会给服务器带来很大的压力。大量的数据爬取会导致服务器崩溃,对网站所属公司的利益造成损害。但少量数据不会影响服务器的正常运行。因此,为了演示目的,我们只爬取了2017级学生的课表。
通过for循环和if语句,以及使用函数,我们爬到了2017年的课程表。
内容合并
接下来,我们将整合前面的内容,对爬取的数据进行处理。具体操作如下:
应用这段代码del可以解决我们爬取过程中的截断问题。如果主要是截断,我们可以找出哪些数据我们没有爬取,然后自动化处理。
执行这段代码时,发现浏览器正在自动爬取。 (需要一定的时间)整个爬取完成,但是中间过程可能会被学术老师(反爬虫)拦截。
这里我们只截取一些例子进行展示(小编也很怕学术老师生气)。
后续我们会继续分享这个进阶内容(也可以更改IP地址进行爬取,一旦报错就可以获取数据)。
简单的数据分析
爬取到这个数据后,我们可以对这个数据进行简单的数据分析(比如哪个班级的课最多,哪个老师的课最多)。这里我只展示一些数据处理方法(爬取过程ip地址被教务处禁止了,这说明教务处的反爬虫系统还是很不错的)。
这里我们用函数先聚合老师和count(),然后对值进行排序,看看哪些老师的课多,=False是降序排列,但是由于没有爬取数据,所以排序不出来不完全准确。
部分结果显示
教师时数
数据显示
这些代码徐伯凡同学之前已经解释过了,这里就不做过多解释了。你可以看看第二期画画的内容,还可以画出很多有趣的图画。
输出结果
我们用来显示一些数据。出于隐私问题,我们将部分教师定义为“1、2、3、4、5”。我们可以看到每个老师每学期的课时数。将来,我们可以将这些图表与类进行比较。通过将平均成绩联系起来,我们可以看出老师的授课时数和成绩之间是否存在一定的反比关系。
我们可以根据现有的数据得出很多结果(由于隐私问题,这里不会显示老师的名字)。由于我们在爬取过程中被截获,所以这里只是部分数据,不是全部。这里我们可以思考一下这些老师上课的地点和学生成绩之间的关系,或者上课人数和未来期末考试成绩(爬取期末考试成绩)之间的关系等等,这是一种方式提高教育质量。
也可能存在某种线性关系。下次我们会继续分享一些线性回归的内容,与爬虫结合(爬取一些相关的内容)来探索更大的价值,并对未来进行一定的预测、归因分析等。
爬行动物的法律问题
《关于办理非法利用信息网络、帮助信息网络犯罪活动等刑事案件适用法律若干问题的解释》(法解释[2019]15号)
第四条 拒绝履行信息网络安全管理义务,导致用户信息泄露,有下列情形之一的,视为造成本法第二百八十六条第一款第二项规定的“造成严重后果”:刑法-1:
(一)导致行踪信息、通讯内容、信用信息、财产信息泄露500条以上的;
(二)导致住宿信息、通讯记录、健康生理信息、交易信息等5000条以上用户信息泄露,可能影响人身、财产安全的;
(三)导致第一款、第二款规定以外的用户信息泄露五万条以上的;
严格原则:
1. 不要抓取通常无法访问的内容
2.不要过度爬行给服务器带来压力
3. 不对他人隐私造成任何负面影响
4、不会对网站维护者造成伤害(爬虫模拟多个用户访问网站,并不是网站维护者真正的用户,所以对服务器造成压力,对网站盈利贡献不大维护者)
整体代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from bs4 import BeautifulSoup #分析html数据格式
import requests #向服务器发送请求并获取数据
import pandas as pd #便于时候的数据分析
def getContents(elements):
page = {} #定义了page字典
ind = [] #定义了一些空列表,这些空列表就是网页的内容
cla = []
wee = []
nam = []
sco = []
roo = []
tea = []
mer = []
dep = []
cou = []
for i in range(len(elements)): #运用了一个for循环,这个lens就是传入soup.container的内容
ind.append(elements[i].select('td')[0].text) #利用append将其所有的信息追加到列表中去
cla.append(elements[i].select('td')[1].text)
wee.append(elements[i].select('td')[2].text)
nam.append(elements[i].select('td')[3].text)
sco.append(elements[i].select('td')[4].text)
roo.append(elements[i].select('td')[5].text)
tea.append(elements[i].select('td')[6].text)
#ran.append(elements[i].select('td')[7].text)
mer.append(elements[i].select('td')[7].text)
dep.append(elements[i].select('td')[8].text)
cou.append(elements[i].select('td')[9].text)
page['序号'] = ind #规整地存到字典中去
page['班级'] = cla
page['课程安排'] = wee
page['课程名'] = nam
page['学分'] = sco
page['教室'] = roo
page['老师'] = tea
page['合班'] = mer
page['学院'] = dep
page['学生人数'] = cou
return pd.DataFrame(page) #返回到dataframe中
browser = webdriver.Chrome(r'C:\Program Files (x86)\Google\Chrome\Application\chromedriver') #声明浏览器对象
browser.get('http://jwc.nau.edu.cn/coursearrangeInfosearch.aspx')
ls=browser.find_elements_by_css_selector('#Term+select+select')[0]
class_name = [i[1:] for i in ls.text.split('\n')]
class_name = [i[1:] for i in ls.text.split('\n')]
filter_name = []
for i in class_name:
if i[:4]=='2017':
filter_name.append(i)
for i in filter_name:
# browser.get('http://jwc.nau.edu.cn/coursearrangeInfosearch.aspx')
ls = browser.find_elements_by_css_selector('#Term+select+select')[0]
ls.send_keys(i)
btn = browser.find_element_by_id('searchBtn')
btn.send_keys(Keys.ENTER)
soup = BeautifulSoup(browser.page_source, "html.parser")
elements = soup.select('.container tr')[1:-1]
if flag: #做一个判断的合并
total = getContents(elements) #将网页内容复制给tatal变量
flag = False
else:
total = pd.concat([total, getContents(elements)]) #将这些很多地dataframe合并在一起
print(i)
del filter_name[filter_name.index(i)]
total.groupby('老师').count().sort_values(by='序号', ascending=False)
total.to_csv('总课表.csv',encoding='gbk')
total = pd.read_csv('总课表.csv', encoding='gbk').iloc[:,1:]
total.groupby(by='老师').count().sort_values(by='序号',ascending = False).head(20)