用Python爬虫爬取广州大学教务系统的成绩(内网访问)
在进行爬取前,首先要了解:
1、什么是CSS选择器?
每一条css样式定义由两部分组成,形式如下: [code] 选择器{样式} [/code] 在{}之前的部分就是“选择器”。
“选择器”指明了{}中的“样式”的作用对象,也就是“样式”作用于网页中的哪些元素。
可参考:
http://www.w3school.com.cn/cssref/css_selectors.asp
http://www.ruanyifeng.com/blog/2009/03/css_selectors.html
2、常用的三种网页抓取方法(例子可能不可用,只要看方法就可以了)
正则表达式:
1 # -*- coding: utf-8 -*- 2 3 import urllib2 4 import re 5 6 7 def scrape(html): 8 area = re.findall(‘<tr id="places_area__row">.*?<td\s*class=["\‘]w2p_fw["\‘]>(.*?)</td>‘, html)[0] 9 return area 10 11 12 if __name__ == ‘__main__‘: 13 html = urllib2.urlopen(‘http://example.webscraping.com/view/United-Kingdom-239‘).read() 14 print scrape(html)
流行的BeautifulSoup模块:
1 # -*- coding: utf-8 -*- 2 3 import urllib2 4 from bs4 import BeautifulSoup 5 6 def scrape(html): 7 soup = BeautifulSoup(html) 8 tr = soup.find(attrs={‘id‘:‘places_area__row‘}) # locate the area row 9 # ‘class‘ is a special python attribute so instead ‘class_‘ is used 10 td = tr.find(attrs={‘class‘:‘w2p_fw‘}) # locate the area tag 11 area = td.text # extract the area contents from this tag 12 return area 13 14 if __name__ == ‘__main__‘: 15 html = urllib2.urlopen(‘http://example.webscraping.com/view/United-Kingdom-239‘).read() 16 print scrape(html)
强大的lxml模块:
1 # -*- coding: utf-8 -*- 2 3 import urllib2 4 import lxml.html 5 6 7 def scrape(html): 8 tree = lxml.html.fromstring(html) 9 td = tree.cssselect(‘tr#places_neighbours__row > td.w2p_fw‘)[0] 10 area = td.text_content() 11 return area 12 13 if __name__ == ‘__main__‘: 14 html = urllib2.urlopen(‘http://example.webscraping.com/view/United-Kingdom-239‘).read() 15 print scrape(html)
本文选用第三种网页抓取的方法:lxml(性能快,使用难度简单,只是安装难度相对困难而已,建议直接安装anaconda)
3、什么是cookie?
在 Internet 中,Cookie 实际上是指小量信息,是由 Web 服务器创建的,将信息存储在用户计算机上的文件。一般网络用户习惯用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 Session 跟踪而存储在用户本地终端上的数据,而这些数据通常会经过加密处理。
通常情况下,当用户结束浏览器会话时,系统将终止所有的 Cookie。当 Web 服务器创建了Cookies 后,只要在其有效期内,当用户访问同一个 Web 服务器时,浏览器首先要检查本地的Cookies,并将其原样发送给 Web 服务器。这种状态信息称作“Persistent Client State HTTP Cookie” ,简称为 Cookies。
具体含义:
“Cookie”是小量信息,由网络服务器发送出来以存储在网络浏览器上,从而下次这位独一无二的访客又回到该网络服务器时,可从该浏览器读回此信息。这是很有用的,让浏览器记住这位访客的特定信息,如上次访问的位置、花费的时间或用户首选项(如样式表)。Cookie 是个存储在浏览器目录的文本文件,当浏览器运行时,存储在 RAM 中。一旦你从该网站或网络服务器退出,Cookie 也可存储在计算机的硬驱上。当访客结束其浏览器对话时,即终止的所有 Cookie。
主要用途:
服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是Cookies的功用。另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入Cookies,以便在最后付款时提取信息。
4、csv文件
逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。
可以看成是我们常见的excel文件,只不过是用逗号分隔每一个单元格而已。
完整代码如下:
1 # -*- coding: utf-8 -*- 2 3 import urllib 4 import urllib2 5 import cookielib 6 import lxml.html 7 import csv 8 9 # 用户名、密码 10 LOGIN_USERNAME = ‘1406100037‘ 11 LOGIN_PASSWORD = ‘******‘ 12 13 LOGIN_URL1 = ‘https://cas.gzhu.edu.cn/cas_server/login‘ 14 LOGIN_URL2 = ‘http://202.192.18.189/login_gzdx.aspx‘ 15 16 17 def parse_form(html): 18 ‘‘‘ 19 获取表单提交所需的所有隐藏域 20 :param html: html代码 21 :return: 该页面的表单提交所需的所有隐藏域 22 ‘‘‘ 23 tree = lxml.html.fromstring(html) 24 data = {} 25 for e in tree.cssselect(‘form input‘): 26 if e.get(‘name‘): 27 data[e.get(‘name‘)] = e.get(‘value‘).encode(‘utf-8‘) 28 return data 29 30 31 def getRecordsHTML(): 32 ‘‘‘ 33 发送POST请求提交表单 34 使用cookie登录数字广大 35 再次使用cookie登录"http://202.192.18.189/login_gzdx.aspx" 36 然后再次发送POST请求提交表单查询成绩 37 :return:查询成绩的html 38 ‘‘‘ 39 mcj = cookielib.MozillaCookieJar(‘mcj.txt‘) 40 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(mcj)) 41 html = opener.open(LOGIN_URL1).read() 42 data = parse_form(html) 43 data[‘username‘] = LOGIN_USERNAME 44 data[‘password‘] = LOGIN_PASSWORD 45 encoded_data = urllib.urlencode(data) 46 request = urllib2.Request(LOGIN_URL1, encoded_data) 47 response = opener.open(request) 48 print(response.geturl()) 49 50 request = urllib2.Request(LOGIN_URL2, encoded_data) 51 response = opener.open(request) 52 print(response.geturl()) 53 54 html = opener.open(response.geturl()).read() 55 tree = lxml.html.fromstring(html) 56 path = tree.cssselect(‘#headDiv > ul > li:nth-child(6) > ul > li:nth-child(1) > a‘)[0].get(‘href‘) 57 URL3 = ‘http://202.192.18.185/‘ + 58 urllib.quote(path.encode(‘gbk‘), safe=‘?=&‘) 59 print(URL3) 60 61 html = opener.open(URL3).read() 62 data = parse_form(html) 63 newData = { 64 ‘__VIEWSTATE‘: data[‘__VIEWSTATE‘], 65 ‘__VIEWSTATEGENERATOR‘: data[‘__VIEWSTATEGENERATOR‘], 66 ‘Button2‘: data[‘Button2‘] 67 } 68 # print(‘data=‘, newData) 69 70 encoded_data = urllib.urlencode(newData) 71 request = urllib2.Request(URL3, encoded_data) 72 response = opener.open(request) 73 mcj.save(ignore_discard=True, ignore_expires=True) 74 html = response.read() 75 return html 76 77 78 def main(): 79 ‘‘‘ 80 提取并保存成绩到“在校学习成绩.csv”文件中 81 ‘‘‘ 82 writer = csv.writer(open(‘在校学习成绩.csv‘, ‘w‘)) 83 tree = lxml.html.fromstring(getRecordsHTML()) 84 row = [] 85 86 for i in xrange(1, 100): 87 for j in xrange(15): 88 try: 89 row.append(tree.cssselect(‘#Datagrid1 > tr:nth-child(%s) > td‘ % i)[j].text_content().encode(‘utf-8‘)) 90 except Exception as e: 91 break 92 writer.writerow(row) 93 row = [] 94 95 if __name__ == ‘__main__‘: 96 main()
运行结果:
生成的csv文件如下:
因为上面的代码已经将cookie信息保存下来了,下次访问我们就可以用下面的代码:
1 # -*- coding: utf-8 -*- 2 3 import urllib 4 import urllib2 5 import cookielib 6 import lxml.html 7 import csv 8 9 def parse_form(html): 10 ‘‘‘ 11 获取表单提交所需的所有隐藏域 12 :param html: html代码 13 :return: 该页面的表单提交所需的所有隐藏域 14 ‘‘‘ 15 tree = lxml.html.fromstring(html) 16 data = {} 17 for e in tree.cssselect(‘form input‘): 18 if e.get(‘name‘): 19 data[e.get(‘name‘)] = e.get(‘value‘).encode(‘utf-8‘) 20 return data 21 22 def getRecordsHTML(): 23 mcj = cookielib.MozillaCookieJar() 24 mcj.load(‘mcj.txt‘, ignore_discard=True, ignore_expires=True) 25 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(mcj)) 26 URL3 = ‘http://202.192.18.185/xscj_gc.aspx?xh=1406100037‘ 27 html = opener.open(URL3).read() 28 data = parse_form(html) 29 newData = { 30 ‘__VIEWSTATE‘: data[‘__VIEWSTATE‘], 31 ‘__VIEWSTATEGENERATOR‘: data[‘__VIEWSTATEGENERATOR‘], 32 ‘Button2‘: data[‘Button2‘] 33 } 34 35 encoded_data = urllib.urlencode(newData) 36 request = urllib2.Request(URL3, encoded_data) 37 response = opener.open(request) 38 html = response.read() 39 return html 40 41 42 def main(): 43 writer = csv.writer(open(‘在校学习成绩2.csv‘, ‘w‘)) 44 tree = lxml.html.fromstring(getRecordsHTML()) 45 row = [] 46 47 for i in xrange(1, 100): 48 for j in xrange(15): 49 try: 50 row.append(tree.cssselect(‘#Datagrid1 > tr:nth-child(%s) > td‘ % i)[j].text_content().encode(‘utf-8‘)) 51 except Exception as e: 52 break 53 writer.writerow(row) 54 row = [] 55 56 if __name__ == ‘__main__‘: 57 main()