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


    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完结

  • 相关阅读:
    线程3 线程池和文件下载服务器
    线程 2
    线程 1
    线程间操作
    编写高质量的代码-------从命名开始
    基于.NET平台常用的框架整理
    消息队列
    我是一个线程
    linux 网络命令
    css hack比较全 --- 转
  • 原文地址:https://www.cnblogs.com/ducklu/p/9032299.html
Copyright © 2020-2023  润新知