爬取锦城学院图书馆学生借书信息

http://jccxxt.scujcc.cn/ReaderLogin.aspx

这个网站爬了我接近三个星期,对,你没听错,先贴上我一直错的code

 1 import requests
 2 from bs4 import BeautifulSoup
 3 import time
 4 import traceback
 5 
 6 def Get__EVENTVALIDATION(Soup):
 7     res = Soup.find(attrs = {'name':'__EVENTVALIDATION'})
 8     return res['value']
 9 
10 def Get__VIEWSTATE(Soup):
11     res = Soup.find(attrs = {'name':'__VIEWSTATE'})
12     return res['value']
13 
14 # def Get__EVENTTARGET(Soup):
15 #     res = Soup.find(attrs = {'name':'__EVENTTARGET'})
16 #     return res['value']
17 
18 # def Get__EVENTARGUMENT(Soup):
19 #     res = Soup.find(attrs = {'name':'__EVENTARGUMENT'})
20 #     return res['value']
21 
22 def login(url, Soup, Sno, session):
23     try:
24         info = {
25             # "ScriptManager1":"UpdatePanel1|ImageButton1",
26             "__EVENTTARGET":'',
27             "__EVENTARGUMENT":'',
28             "__VIEWSTATE":Get__VIEWSTATE(Soup),
29             "__EVENTVALIDATION":Get__EVENTVALIDATION(Soup),
30             # "DropDownList1":"借书证号",
31             "TextBox1":Sno,
32             # "TextBox2":"",
33             # "__ASYNCPOST":"true",
34             # "ImageButton1.x":"1",
35             # "ImageButton1.y":"1"
36         }
37         header = {
38             # 'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
39             'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36',
40             'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
41             'Accept-Encoding':'gzip, deflate',
42             'Accept-Language':'zh-CN,zh;q=0.9',
43             'Referer':'http://jccxxt.scujcc.cn/ReaderLogin.aspx',
44             'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
45             # 'Cookie':'UM_distinctid=162f7c3dcc4420-07d6206f36b7a6-b353461-100200-162f7c3dcc56a; yunsuo_session_verify=aa35d988c77a05529e4b35a753866ad6; ASP.NET_SessionId=xo5txp3z2xtn2n55xhza2ouz',
46             'Host':'jccxxt.scujcc.cn'
47             # 'Proxy-Connection':'keep-alive'
48         }
49         r = session.post(url, data = info, headers = header)
50         time.sleep(3)
51         return r.text
52     except:
53         traceback.print_exc()
54         return print('post不成功')
55 
56 def main():
57     with requests.Session() as session:
58         url = "http://jccxxt.scujcc.cn/ReaderLogin.aspx"
59         html = session.get(url).text
60         Soup = BeautifulSoup(html, 'html.parser')
61         html_login = login(url, Soup, "163020397", session)
62         Soup_login = BeautifulSoup(html_login, 'html.parser')
63 
64         print(Soup_login.prettify())
65         if Soup_login.find('span', attrs = {'class':'TableContent1'}) is not None:
66             print('Success')
67         else:
68             print('Fail')
69 
70 main()

解释下我的心路历程:

先开始爬这个网站的时候,什么都不知道,以为提交一个用户名(name='TextBox1')就行了,后来发现自己太天真(ps:有很多人是没有密码的)

这个网站居然隐藏了4个hidden字段的表单,你每刷新一次页面,这些field(字段)是会变的

所以我们要使用会话Session,Session详见我的blog:http://www.cnblogs.com/ducklu/p/9026743.html

 

 

回了Session以后,我发现还是不行

我又去不断研究,后来知道提交表单的时候有两种情况:

1.所有你知道的表单项都要提交

2.蜜罐!!!就是有些其实是不用提交的,这个网站就看你提交这个字段没有,如果提交了,他就知道你不是“人”了!!!

 

然后我就得到了,最后这段code,我不断更改里面的字段值,发现还是不行,这时我又懵逼了

 

然后,我又去研究,学到了一个新知识,selenium,哇,这个真的是神器(我可以直接通过浏览器模拟登陆),我在之后会对官方文档写一篇详细的解读的blog

于是,又在一番折磨下,我终于成功了!!!贴上代码,里面有我的详细注释

 1 import sqlite3
 2 import time
 3 import unittest
 4 from selenium import webdriver
 5 from selenium.webdriver.common.keys import Keys
 6 from selenium.webdriver.support.ui import Select
 7 
 8 # con = sqlite3.connect('jcLib.sqlite')
 9 # con.close()
10 class JCLibScrapy(unittest.TestCase):
11 
12     def setUp(self):
13         self.con = sqlite3.connect('jcLib.sqlite')
14 
15     # 每个测试方法均以 test 开头,否则是不被unittest识别的。
16     def test_running(self):
17         driver = webdriver.Chrome('E:/chromedriver.exe')
18         for i in range(1, 450):
19             if (int(i / 100)):
20                 Sno = '163020' + str(i)    
21             elif (int(i / 10)):
22                 Sno = '1630200' + str(i)
23             else:
24                 Sno = '16302000' + str(i)
25             
26             driver.get("http://jccxxt.scujcc.cn/ReaderLogin.aspx")
27             elem = driver.find_element_by_name('TextBox1')
28             elem.clear()
29             elem.send_keys(Sno)
30             time.sleep(3)
31             elem.send_keys(Keys.RETURN)
32             time.sleep(3)
33             # 访问太快了得不到想要的page,必须要停滞一会
34             # print(driver.page_source)
35 
36             # 存储结果
37             self.res = {}
38             #存储借的books
39             books = []
40 
41             # 已经进入了我们要爬取的页面,我们只需要获得想要的info即可
42             # 不知道tr有多少,所以用异常处理遇到没有的tr跳出
43             for i in range(2, 100):
44                 try:
45                     # 这里有个很重要的点,我在阅读了官方文档后并没有发现,那就是这里只能找elements!!!,不能直接找他的属性,因为我们用的是find_element
46                     # 我先开始的错误写法 '//*[@id="DataGrid1"]/tbody/tr[' + str(i) + ']/td[2]/text()'
47                     # 因为不能直接获取属性,我们只能获取Elment(学过js都知道,getElementById!!!)
48                     elem_name = driver.find_element_by_xpath('//*[@id="LblreaderName"]')
49                     # 获取属性用这个
50                     # res = elem.get_attribute('id')
51                     self.res['name'] = elem_name.text
52 
53                     elem_books = driver.find_element_by_xpath('//*[@id="DataGrid1"]/tbody/tr[' + str(i) + ']/td[2]')
54                     book = elem_books.text
55                     books.append(book)
56                     # print(elem)
57                 except:
58                     # 说明超出范围了,同时也说明获取完了,所以这个时候更新res并且入库
59                     if self.res:
60                         self.res['book'] = books
61                         self.res['Sno'] = Sno
62                         self.InDB()
63                     # 如果登录不成功,则重启浏览器,并且break,不入库
64                     else:
65                         driver.close()    
66                         driver = webdriver.Chrome('E:/chromedriver.exe')            
67                     break
68         driver.close()
69 
70     # 把res入库
71     def InDB(self):
72             cu = self.con.cursor()
73             insert_sql = 'insert into SBook (name, book, Sno) values ("{}", "{}", "{}")'.format(self.res['name'], self.res['book'], self.res['Sno'])
74             cu.execute(insert_sql)
75             self.con.commit()
76             # 记得字典要清空,要不无法判断登录是否成功
77             res = {}
78 
79     def tearDown(self):
80         self.con.close()
81 
82 if __name__ == '__main__':
83     unittest.main()

 附上我的数据库信息

 

然后你会发现,有很多人是设有密码的,这个时候我就想,枚举不就行了吗,后来我想了一下时间复杂度,哇,是n的n次方量级的啊,算到天昏地暗都算不出来(除非它密码短)

所以,现在,我准备研究一个破解密码的算法,此篇blog完结

posted @ 2018-05-13 15:36  duck_lu  阅读(966)  评论(0编辑  收藏  举报