精华内容
下载资源
问答
  • python3爬虫模拟登录爬取豆瓣电影数据

    千次阅读 热门讨论 2019-01-16 16:42:27
    折腾了一天半,总算解决了豆瓣需要登录和输入验证码才能继续爬数据的问题. 故事是这样的,我有一份媒资数据表,表里面都是影片数据,包括:导演\演员\影片类型等等.但是这份数据表的数据缺失太多了,也没有对应上最新的...

    前面说一些背景

    大佬万福,若有高见,还请不吝赐教。
    折腾了一天半,总算解决了豆瓣数据的爬取问题。
    -------需要登录和输入验证码才能继续爬数据的问题。

    你可以获得数据:

    """
    链接: https://pan.baidu.com/s/1StbBu4DDh0dQAwf8Ph5I9g 提取码: up6r 
    """
    

    详细代码可以参照我的github

    """
    lets begin
    """
    

    故事是这样的,我有一份媒资数据表,表里面都是影片数据,包括:导演\演员\影片类型等等.但是这份数据表的数据缺失太多了,也没有对应上最新的豆瓣评分.
    为了建立影片之间的相互关系,需要尽可能的补充影片的各项属性.于是,爬取豆瓣数据来丰富该数据表成为首选解决方案.

    具体的实现思路,是根据我数据库中的影片名称在豆瓣网站上搜索,寻找最佳topk 匹配的影片信息,然后下载如影片的海报,评分,年份等等信息.

    想过用scrapy神框架,但是考虑到我是用一个一个数据进行搜索的,框架带给我的便利不是特别大.再者我对scrapy还不是很熟(其实就看了两天书和几篇博文),所以我毅然放弃此大杀器,用requests和xpath 实现我的需求。

    我们发现,当我使用如下网址:“https://movie.douban.com/j/subject_suggest?q=” + “电影名称” (后面加上我的电影名称之后),他会返回给我该电影的信息,或者返回给我该电影从名称上看比较类似的信息.

    在这里插入图片描述

    比如我搜终结者--------------“https://movie.douban.com/j/subject_suggest?q=终结者

    在这里插入图片描述
    仔细观看网页返回给我的json数据,我发现非常容易就可以解读出电影的海报地址(“img”),以及指向电影的详细信息的链接(“url”).
    拿其中的第一条来看:

        {"episode":"",
        "img":"https://img3.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p1910909085.webp",
        "title":"终结者2:审判日",
        "url":"https:\/\/movie.douban.com\/subject\/1291844\/?suggest=%E7%BB%88%E7%BB%93%E8%80%85",
        "type":"movie",
        "year":"1991",
        "sub_title":"Terminator 2: Judgment Day",
        "id":"1291844"},
    

    所以我的行为变得相对简单:
    1、将mainURL = “https://movie.douban.com/j/subject_suggest?q=” 和电影名称组合起来,形成mainURL +NAME 的url。
    2、request.get 每一个url ,分别获得response。此response的内容是一个json,解析该json即获得海报地址和电影详情页链接m_url。
    3、对海报地址和详情页链接稍加处理(变成规范的url形式,基本内容不变。本例中,即把"/" 全部replace为"/" 即可)
    4、直接存储海报。(urllib.request.urlretrieve(img,filename)直接存储至本地)
    5、继续request.get (m_url) 电影详情页。获得所需要的电影信息。查看源代码,我们知道电影的相关信息都包裹在<script type="application/ld+json">中,
    与电影相关的电影信息包裹在div[@class="recommendations-bd"] 中,
    借助于xpath 于是可以通过以下代码来解析:

        #影片信息搜集
        def summaryCraw(url):
            while True:
                try:
                    time.sleep(1)
                    mresponse = requests.get(url, headers={'User-Agent': random.choice(User_Agents)},proxies=ipGet()).content
                    break
                except:
                    time.sleep(300)
                    print("summaryCraw try to reconnect....")
            if len(mresponse):
                html = etree.HTML(mresponse, parser=etree.HTMLParser(encoding='utf-8'))
                mInfo = html.xpath('//script[@type="application/ld+json"]/text()')
                recommendation_m = html.xpath('//div[@class="recommendations-bd"]//img/@alt')
            else:
                return 0
            return mInfo,recommendation_m
    

    在这里插入图片描述
    在这里插入图片描述

    如何应对反爬虫?
    访问次数增加时,豆瓣会要求用户登录才能取得以上信息,当访问频率过高的时候,IP可能会被封掉。
    有一些大佬解决过类似的问题:
    比如:https://blog.csdn.net/qingminxiehui/article/details/81671161
    比如:https://blog.csdn.net/loner_fang/article/details/81132571
    一些反爬虫策略:https://www.cnblogs.com/micro-chen/p/8676312.html
    爬虫与反爬虫和之后的反反爬虫:https://www.zhihu.com/question/28168585

    一般来说,网站反爬虫有以下的策略:

    1. 同ip请求过于频繁,封ip
    2. 同账号请求过于频繁,封账号
    3. 将页面内容封装在js代码里面异步加载
    4. 需要预登录

    爬虫采取的反击有以下:

    1. 在请求的头部加入user-agent伪装成浏览器
    2. 在请求头部加入cookie对付需要登录才能看的网站

    本人采取的是先登录后爬取,并使用代理ip,使用多个账号。
    这是豆瓣登录页面请求信息(包含验证码):
    在这里插入图片描述
    我们将账号信息封装成这样的表单形式,然后Session.post 提交实现登录。
    如果有验证码,就将验证码存储在本地,然后手动输入验证码。封装成如上表单形式,实现提交。

    综上具体的实现步骤为:
    1、代理ip池的建立。
    “”"
    1、抓取西刺代理网站的代理ip
    2、并根据指定的目标url,对抓取到ip的有效性进行验证
    3、最后存到指定的path
    4、将存储的ip 设定为request.get时使用的代理ip格式。proxies的格式是一个字典: {‘http’: ‘http://122.114.31.177:808‘}
    “”"
    代码引自:https://blog.csdn.net/OnlyloveCuracao/article/details/80968233

    import threading
    import random
    import requests
    import  datetime
    from bs4 import  BeautifulSoup
    
    # ------------------------------------------------------文档处理--------------------------------------------------------
    # 写入文档
    def write(path,text):
        with open(path,'a', encoding='utf-8') as f:
            f.writelines(text)
            f.write('\n')
    # 清空文档
    def truncatefile(path):
        with open(path, 'w', encoding='utf-8') as f:
            f.truncate()
    # 读取文档
    def read(path):
        with open(path, 'r', encoding='utf-8') as f:
            txt = []
            for s in f.readlines():
                txt.append(s.strip())
        return txt
    # ----------------------------------------------------------------------------------------------------------------------
    # 计算时间差,格式: 时分秒
    def gettimediff(start,end):
        seconds = (end - start).seconds
        m, s = divmod(seconds, 60)
        h, m = divmod(m, 60)
        diff = ("%02d:%02d:%02d" % (h, m, s))
        return diff
    # ----------------------------------------------------------------------------------------------------------------------
    # 返回一个随机的请求头 headers
    def getheaders():
        user_agent_list = [ \
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" \
            "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", \
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", \
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", \
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", \
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", \
            "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", \
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", \
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", \
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
        ]
        UserAgent=random.choice(user_agent_list)
        headers = {'User-Agent': UserAgent}
        return headers
    # -----------------------------------------------------检查ip是否可用----------------------------------------------------
    def checkip(targeturl,ip):
        headers =getheaders()  # 定制请求头
        proxies = {"http": "http://"+ip, "https": "http://"+ip}  # 代理ip
        try:
            response=requests.get(url=targeturl,proxies=proxies,headers=headers,timeout=5).status_code
            if response == 200 :
                return True
            else:
                return False
        except:
            return False
    
    #-------------------------------------------------------获取代理方法----------------------------------------------------
    # 免费代理 XiciDaili
    def findip(type,pagenum,targeturl,path): # ip类型,页码,目标url,存放ip的路径
        list={'1': 'http://www.xicidaili.com/nt/', # xicidaili国内普通代理
              '2': 'http://www.xicidaili.com/nn/', # xicidaili国内高匿代理
              '3': 'http://www.xicidaili.com/wn/', # xicidaili国内https代理
              '4': 'http://www.xicidaili.com/wt/'} # xicidaili国外http代理
        url=list[str(type)]+str(pagenum) # 配置url
        headers = getheaders() # 定制请求头
        html=requests.get(url=url,headers=headers,timeout = 5).text
        soup=BeautifulSoup(html,'lxml')
        all=soup.find_all('tr',class_='odd')
        for i in all:
            t=i.find_all('td')
            ip=t[1].text+':'+t[2].text
            is_avail = checkip(targeturl,ip)
            if is_avail == True:
                write(path=path,text=ip)
                print(ip)
    
    #-----------------------------------------------------多线程抓取ip入口---------------------------------------------------
    def getip(targeturl,path):
         truncatefile(path) # 爬取前清空文档
         start = datetime.datetime.now() # 开始时间
         threads=[]
         for type in range(4):   # 四种类型ip,每种类型取前三页,共12条线程
             for pagenum in range(3):
                 t=threading.Thread(target=findip,args=(type+1,pagenum+1,targeturl,path))
                 threads.append(t)
         print('开始爬取代理ip')
         for s in threads: # 开启多线程爬取
             s.start()
         for e in threads: # 等待所有线程结束
             e.join()
         print('爬取完成')
         end = datetime.datetime.now() # 结束时间
         diff = gettimediff(start, end)  # 计算耗时
         ips = read(path)  # 读取爬到的ip数量
         print('一共爬取代理ip: %s 个,共耗时: %s \n' % (len(ips), diff))
    
    #-------------------------------------------------------启动-----------------------------------------------------------
    if __name__ == '__main__':
        path = 'ip.txt' # 存放爬取ip的文档path
        targeturl = 'http://www.cnblogs.com/TurboWay/' # 验证ip有效性的指定url
        getip(targeturl,path)
    

    2、申请多个账号
    每次登陆随机使用多个账号中的一个。
    3、隔一段时间登陆

    while True:
    	try:
    		time.sleep(random.random()*5)
    		do spider......
    

    4、登录时使用不同的header模拟不同的浏览器。
    我使用的是开源包:UserAgent

    from fake_useragent import UserAgent
    ua = UserAgent(verify_ssl=False)
    #如果你的IDE执行ua = UserAgent()报错,请添加verify_ssl=False
    

    关于登陆、验证码存储和输入的代码如下:

    # -*- coding: utf-8 -*- 
    # @Time    : 19-1-16 下午2:35 
    # @Author  : jayden.zheng 
    # @FileName: login.py 
    # @Software: PyCharm 
    # @content :
    
    import requests
    import urllib.request
    from lxml import etree
    import random
    
    #在此之前先构建好代理ip池
    #每次登陆使用不同的代理ip
    def login(session,agents,proxies):
        name_pass = {'@163.com': '98', '@qq.com': 'w534', '@qq.com': 'q98', '18300@qq.com': 'qw98'}
        url = 'https://www.douban.com/accounts/login'
        #proxies_ = ipGet()
        captchav,captchai = get_captcha(url,agents,proxies)
        email = random.sample(name_pass.keys(), 1)[0]
        passwd = name_pass[email]
    
        if len(captchav)>0:
            '''此时有验证码'''
            #人工输入验证码
            urllib.request.urlretrieve(captchav[0],"/home/lenovo/dev/captcha.jpg")
            captcha_value = input('查看captcha.png,有验证码请输入:')
            print ('验证码为:',captcha_value)
    
            data={
                "source":"None",
                "redir": "https: // www.douban.com",
                "form_email": email,
                "form_password": passwd,
                "captcha-solution": captcha_value,
                "captcha-id":captchai[0],
                "login": "登录",
            }
        else:
            '''此时没有验证码'''
            print ('无验证码')
    
            data={
                "source":"None",
                "redir": "https: // www.douban.com",
                "form_email": email,
                "form_password": passwd,
                "login": "登录",
            }
        print ('正在登陆中......')
        #print('帐号为: %20s 密码为: %20s'%(email,passwd))
        return session.post(url,data=data,headers= {'User-Agent': agents},proxies=proxies)
    
    #验证码获取
    def get_captcha(url,agents,proxies):
        html = requests.get(url,headers= {'User-Agent': agents},proxies=proxies).content
        html = etree.HTML(html, parser=etree.HTMLParser(encoding='utf-8'))
        captcha_value = html.xpath('//*[@id="captcha_image"]/@src')
        captcha_id = html.xpath('//*[@name="captcha-id"]/@value')
        return captcha_value,captcha_id
    
    
    

    具体的抓取过程代码:

    # -*- coding: utf-8 -*- 
    # @Time    : 19-1-15 下午2:53 
    # @Author  : jayden.zheng 
    # @FileName: spider.py 
    # @Software: PyCharm 
    # @content :
    from lxml import etree
    import requests
    import time
    import urllib3
    import warnings
    import random
    import urllib.request
    import pandas as pd
    from login import  login
    from fake_useragent import UserAgent
    
    #去掉warnings 提示
    warnings.simplefilter(action='ignore', category=FutureWarning)
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    ua = UserAgent(verify_ssl=False)
    
    from wsInput import dataInput
    movie = dataInput()
    mainUrl = "https://movie.douban.com/j/subject_suggest?q="
    
    def getip():
        ipdf = pd.read_csv('ip.txt',header=None)
        ipdf.columns =['ip']
        ipdf['ip'] = 'http://' + ipdf['ip']
        ipdf['ip'] = ipdf['ip'].apply(lambda x:{'http':x})
        return ipdf['ip']
    
    
    #将图片保存至本地
    def outputImg(c2code,img):
        imgTmp = img.split('.')[-1].lower()
        if imgTmp == 'jpg':
            filename = "/home/lenovo/dev/data/Douban/img/" + str(c2code) + ".jpg"
        elif imgTmp == 'png':
            filename = "/home/lenovo/dev/data/Douban/img/" + str(c2code) + ".png"
        elif imgTmp == 'jpeg':
            filename = "/home/lenovo/dev/data/Douban/img/" + str(c2code) + ".jpeg"
        else:
            filename = "/home/lenovo/dev/data/Douban/img/" + str(c2code) + ".pdf"
        urllib.request.urlretrieve(img, filename)
    
    #影片信息搜集
    def summaryCraw(url,agents,proxies):
        while True:
            try:
                time.sleep(random.random()*5)
                mresponse = requests.get(url, headers={'User-Agent': agents},proxies=proxies).content
                break
            except:
                time.sleep(200)
                print("summaryCraw try to reconnect....")
        if len(mresponse):
            html = etree.HTML(mresponse, parser=etree.HTMLParser(encoding='utf-8'))
            mInfo = html.xpath('//script[@type="application/ld+json"]/text()')
            recommendation_m = html.xpath('//div[@class="recommendations-bd"]//img/@alt')
        else:
            return 0
        return mInfo,recommendation_m
    
    
    def infoCompare(response,qstr,movie,agents,proxies):
        imageDf = pd.DataFrame()
        c2code = movie[movie['NAME'] == qstr]['C2CODE'].iloc[0]
        imageLst = []
        movieUrlLst = []
        yearLst = []
        nameLst = []
        minfoLSt = []
        recommendationLst = []
    
        for item in eval(response):
            if qstr in item['title'] and 'img' and 'url' and 'year' in item or len(response) == 1:
                img = item['img'].replace('\\/','/')
                url = item['url'].replace('\\/','/')
                nameLst.append(item['title'])
                imageLst.append(img)
                movieUrlLst.append(url)
                yearLst.append(item['year'])
                print("img store ------------")
                print(img)
                outputImg(c2code, img)
                mInfo, recommendation_m = summaryCraw(url,agents,proxies)
                minfoLSt.append(mInfo)
                recommendationLst.append(recommendation_m)
                c2code = c2code + "_"
    
            else:
                continue
    
        imageDf['name'] = nameLst
        imageDf['img'] = imageLst
        imageDf['url'] = movieUrlLst
        imageDf['year'] = yearLst
        imageDf['mInfo'] = minfoLSt
        imageDf['recommendation_m'] = recommendationLst
        return imageDf
    
    
    def targetUrl(mainUrl,qstr,agents,proxies):
        while True:
            try:
                time.sleep(random.random()*3)
                response = requests.get(mainUrl + qstr,headers= {'User-Agent': agents},proxies = proxies).text
                break
            except:
                time.sleep(120)
                print("targetUrl try to reconnect....")
        return response
    
    
    def urlCollect(mainUrl,movie,ipLst):
    
        movieLst = movie['NAME']
        mlen = len(movie)
        urlDf = pd.DataFrame()
        crawlcount  = 1
        for qstr in movieLst:
            print("\ncraw times %d / %d ---@--- %s -------------->"%(crawlcount,mlen,qstr))
    
            session = requests.Session()
            agents = ua.random
    
            proxies = random.choice(ipLst)
    
            req = login(session,agents,proxies)
            print(req)
            response = targetUrl(mainUrl,qstr,agents,proxies)
    
            crawlcount = crawlcount + 1
            if len(response):
    
                imageDf = infoCompare(response,qstr,movie,agents,proxies)
                urlDf = pd.concat([urlDf,imageDf],sort=True)
                if crawlcount % 100 == 0:
                    urlDf.to_csv("urlDf.csv")
            else:
                continue
        return urlDf
    
    
    
    ipLst = getip()
    urlDf = urlCollect(mainUrl,movie,ipLst)
    print(urlDf)
    urlDf.to_csv("urlDf.csv")
    
    
    

    详细代码可以参照我的github

    展开全文
  • 今天来写写爬取教务系统的爬虫,此次的爬虫目的是爬取教务系统里面的成绩单,涉及到的库依旧是selenium,re,beautifulsoup,Options,今天多了个csv库用来处理爬取的数据,使其生成相应的csv文件,可用于excel和txt...

    前言

    今天来写写爬取教务系统的爬虫,此次的爬虫目的是爬取教务系统里面的成绩单,涉及到的库依旧是selenium,re,beautifulsoup,Options,今天多了个csv库用来处理爬取的数据,使其生成相应的csv文件,可用于excel和txt打开,好了,废话不多说,开始步骤

    具体步骤

    ①首先要设定好chromedriver终端程序文件的路径以及生成文件的路径,还有登录的账号密码

    #模拟登陆终端文件路径
    driver_path = r'E:\py\chromedriver\chromedriver.exe'
    
    #生成csv文件路径
    csv_file_path = r'E://py//教务系统成绩表.csv'
    
    #登录教务系统的账号与密码
    UserId = '账号' #
    PassWord = '密码' #
    

    ②对chromedriver一些参数的设定,代码注释有说明
    chrome的定义i里面的executable_path是chromedriver.exe的路径
    当然,调用参数 首先要接入Options库

    #实现后台登陆浏览器
    chrome_options = Options()
    chrome_options.add_argument('--headless')#关闭浏览器,后台运行,即不会打开浏览器
    chrome_options.add_argument('--disable-gpu')#禁止GUP为浏览器加速 防止过多开启浏览器卡死
    #更改代理ip防反爬虫
    #chrome_options.add_argument(f"--proxy-server=121.52.208.200:808")
    
    driver = webdriver.Chrome(executable_path = driver_path, chrome_options=chrome_options)
    

    接入接口

    from selenium.webdriver.chrome.options import Options
    

    ③一系列模拟登录操作,以达到可用获取成绩单页面的html,分别运用的driver的查找元素功能,send_keys()里面存放的是给与的输入值,click()是单击按钮
    最后在每个页面加载时给程序停顿时间,防止加载页面过慢,导致下一步操作未能实现

    driver.get('http://jwgln.zsc.edu.cn/jsxsd/')
    time.sleep(5)
    
    #输入登录账号
    try:
        driver.find_element_by_id("userAccount").send_keys(UserId)
        print('输入账号成功!')
    except:
        print('输入账号失败!')
    # 输入登录密码
    try:
        driver.find_element_by_id("userPassword").send_keys(PassWord)
        print('输入密码成功!')
    except:
        print('输入密码失败!')
    # 点击登录
    try:
        driver.find_element_by_xpath('//*[@id="btnSubmit"]').click()  # 用click模拟浏览器点击
        print('正在登录...')
    except:
        print('登录失败!')
    driver.implicitly_wait(3)
    if '用户名或密码错误' in driver.page_source:
        print('登录失败,用户名或密码错误,请查证账号密码是否准确。')
        exit(0)
    else:
        print('登录成功!')
    # 点击学业情况
    try:
        driver.find_element_by_xpath('//*[@class="block5"]').click()
        print('点击学业情况成功!')
    except:
        print('点击学业情况失败!')
    driver.implicitly_wait(3)
    
    #点击课程成绩查询
    try:
        driver.find_element_by_xpath('//*[@href="/jsxsd/kscj/cjcx_query"]').click()
        time.sleep(3)
        driver.find_element_by_xpath('//*[@id="btn_query"]').click()
        print('课程成绩查询成功!')
    except:
        print('课程成绩查询失败!')
    
    

    ④当然模拟登录就是为了获取此网页html,但是笔者多次一步获取此网页的cookie,然后再用request请求网页,得到网页信息,主要是为了以后某需要登录网页做准备。

    cookies = driver.get_cookies()
    cookies_list= []
    for cookie_dict in cookies:
        cookie =cookie_dict['name']+'='+cookie_dict['value']
        cookies_list.append(cookie)
    header_cookie = ';'.join(cookies_list)
    
    #关闭模拟终端
    driver.quit()
    

    上面的cookies_list存放着从driver获取的并且经过处理过可以放入头部信息的cookie

    ⑤获取了cookie,设置好头部,就可以直接拿所要爬取的页面的URL直接请求爬取,无需再登录,下面还有运用beautifulsoup对数据进行筛选的操作

    #设置好页面请求头部
    headers = {
           'cookie':header_cookie,
           'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    }
    
    #需要抓取信息的页面URL
    fin_url = 'http://jwgln.zsc.edu.cn/jsxsd/kscj/cjcx_list'
    response = requests.get(fin_url,headers=headers)
    page_source=response.text
    
    #用bs4进行数据筛选
    bs = BeautifulSoup(page_source, 'lxml')
    my_score_detail = bs.find_all(name='td')[1:]
    my_score_detail = list(my_score_detail)
    my_score_list = [i.string for i in my_score_detail]
    

    ⑥数据过滤好后,就是存储到文件里面,运用csv库来生成格式写入文件

    #数据整理,将数据按原格式存入csv文件,可用excel打开
    try:
        f = open(csv_file_path, 'w', newline='')
        csv_write = csv.writer(f)
        csv_write.writerow(['序号', '开课学期', '课程编号', '课程名称', '总成绩', '学分', '平时成绩', '期中成绩', '实验成绩', '期末成绩', '课程属性', '课程性质', '备注', '考试性质'])
        for i in range(0, len(my_score_list), 14):
            course_list = []
            for j in range(i, i + 14):
                course_list.append(my_score_list[j])
            csv_write.writerow(course_list)
        f.close()
        print('生成csv文件成功!')
    except:
        print('生成csv文件失败')
    

    附加

    下面是一些chrome的暂停操作,可用防止页面加载过慢问题导致爬取出错
    driver就是经过Webdriver定义的driver,name就是网页html标签tag名字,意思就是出现名为name的tag就执行下一步,当然里面的20参数是等待20秒后执行下一步的意思

    需要的接口

    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    

    主要函数

    #暂停防止页面加载太慢出错
    def wait(drive, name):
        try:
            element = WebDriverWait(drive, 20).until(
                EC.presence_of_all_elements_located((By.TAG_NAME, name))
            )
        finally:
            driver.quit()
    

    引用

    wait(driver,name)
    

    再附加

    下面是定义虚拟鼠标来模拟登录的方法,当然要接入接口

    from selenium.webdriver.common.action_chains import ActionChains
    
    #模拟登录鼠标点击方法
    def login(drive):
        actions = ActionChains(drive)
        name_input = drive.find_element_by_id('username')
        actions.move_to_element(name_input)
        actions.send_keys_to_element(name_input, '账号')
    
        psw_input = drive.find_element_by_id('password')
        actions.move_to_element(psw_input)
        actions.send_keys_to_element(psw_input, '密码')
        actions.perform()
        submit_button = drive.find_element_by_xpath('xpath格式')
        submit_button.click()
    
    

    最后放上所有代码

    当然,要运行成功这个代码,肯定需要我们学校ZSC的教务系统所属的学生账号密码

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium.webdriver.support import expected_conditions as EC
    import requests
    from bs4 import BeautifulSoup
    import time
    import csv
    import re
    from prettytable import PrettyTable
    
    # selenium 模拟教务系统查询成绩登陆
    #@author Himit_ZH
    
    #模拟登陆终端文件路径
    driver_path = r'E:\py\chromedriver\chromedriver.exe'
    
    #生成csv文件路径
    csv_file_path = r'E://py//教务系统成绩表.csv'
    
    #登录教务系统的账号与密码
    UserId = '账号'
    PassWord = '密码' 
    
    #实现后台登陆浏览器
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    #更改代理ip防反爬虫
    #chrome_options.add_argument(f"--proxy-server=121.52.208.200:808")
    
    driver = webdriver.Chrome(executable_path = driver_path, chrome_options=chrome_options)
    
    driver.get('http://jwgln.zsc.edu.cn/jsxsd/')
    time.sleep(5)
    
    #输入登录账号
    try:
        driver.find_element_by_id("userAccount").send_keys(UserId)
        print('输入账号成功!')
    except:
        print('输入账号失败!')
    # 输入登录密码
    try:
        driver.find_element_by_id("userPassword").send_keys(PassWord)
        print('输入密码成功!')
    except:
        print('输入密码失败!')
    # 点击登录
    try:
        driver.find_element_by_xpath('//*[@id="btnSubmit"]').click()  # 用click模拟浏览器点击
        print('正在登录...')
    except:
        print('登录失败!')
    driver.implicitly_wait(3)
    if '用户名或密码错误' in driver.page_source:
        print('登录失败,用户名或密码错误,请查证账号密码是否准确。')
        exit(0)
    else:
        print('登录成功!')
    # 点击学业情况
    try:
        driver.find_element_by_xpath('//*[@class="block5"]').click()
        print('点击学业情况成功!')
    except:
        print('点击学业情况失败!')
    driver.implicitly_wait(3)
    
    #点击课程成绩查询
    try:
        driver.find_element_by_xpath('//*[@href="/jsxsd/kscj/cjcx_query"]').click()
        time.sleep(3)
        driver.find_element_by_xpath('//*[@id="btn_query"]').click()
        print('课程成绩查询成功!')
    except:
        print('课程成绩查询失败!')
    
    #获取此页面的cookies
    cookies = driver.get_cookies()
    cookies_list= []
    for cookie_dict in cookies:
        cookie =cookie_dict['name']+'='+cookie_dict['value']
        cookies_list.append(cookie)
    header_cookie = ';'.join(cookies_list)
    
    #关闭模拟终端
    driver.quit()
    
    #设置好页面请求头部
    headers = {
           'cookie':header_cookie,
           'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    }
    
    #需要抓取信息的页面URL
    fin_url = 'http://jwgln.zsc.edu.cn/jsxsd/kscj/cjcx_list'
    response = requests.get(fin_url,headers=headers)
    page_source=response.text
    
    #用bs4进行数据筛选
    bs = BeautifulSoup(page_source, 'lxml')
    my_score_detail = bs.find_all(name='td')[1:]
    my_score_detail = list(my_score_detail)
    my_score_list = [i.string for i in my_score_detail]
    
    
    #数据整理,将数据按原格式存入csv文件,可用excel打开
    try:
        f = open(csv_file_path, 'w', newline='')
        csv_write = csv.writer(f)
        csv_write.writerow(['序号', '开课学期', '课程编号', '课程名称', '总成绩', '学分', '平时成绩', '期中成绩', '实验成绩', '期末成绩', '课程属性', '课程性质', '备注', '考试性质'])
        for i in range(0, len(my_score_list), 14):
            course_list = []
            for j in range(i, i + 14):
                course_list.append(my_score_list[j])
            csv_write.writerow(course_list)
        f.close()
        print('生成csv文件成功!')
    except:
        print('生成csv文件失败')
    
    #暂停防止页面加载太慢出错
    def wait(drive, name):
        try:
            element = WebDriverWait(drive, 20).until(
                EC.presence_of_all_elements_located((By.TAG_NAME, name))
            )
        finally:
            driver.quit()
    
    #模拟登录鼠标点击方法
    def login(drive):
        actions = ActionChains(drive)
        name_input = drive.find_element_by_id('username')
        actions.move_to_element(name_input)
        actions.send_keys_to_element(name_input, '账号')
    
        psw_input = drive.find_element_by_id('password')
        actions.move_to_element(psw_input)
        actions.send_keys_to_element(psw_input, '密码')
        actions.perform()
        submit_button = drive.find_element_by_xpath('xpath格式')
        submit_button.click()
    
    
    展开全文
  • 本篇文章通过学习python爬虫相关知识点来分析Python3爬虫登录模拟的原理以及相关代码分析,对此有兴趣的朋友参考下。
  • Python3爬虫模拟新浪微博登录 初学Python3小白一枚,若有错误请不吝赐教 过程分析 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客...

    Python3爬虫模拟新浪微博登录

    初学Python3小白一枚,若有错误请不吝赐教

    过程分析

    Fiddler抓包登录新浪微博的过程

    整个过程 从填写数据到跳转到主页一共经历了七个步骤:
    1.在登陆前,输入账号结束,失去输入框焦点,浏览器会发送两个请求,分别请求了登陆前加密密码所需的servertime、nonce、pubkey(图中对应3)
    2.第二个ajax请求的是关于验证码的(图中对应4、5)
    3.这个是点击登录按钮后,将加密后的数据post到服务器(图中对应6)
    4.服务器会返回一系列数据,(对应图中的8),它包含了重定向的地址
    5.多次页面加载后,会接收到来自服务器的json数据包(对应图中的19)在这
    个数据包中包含了每个微博用户特定的uniqueid
    6.这是一个携带有相关用户信息的script脚本(对应图中的22)
    7.经过一系列的跳转后,最终跳转到个人主页面

    遇到的坑

    遇到的最严重的坑,就是验证码的啦
    验证码的请求分析,着实耗费了大半天 。这是验证码请求的服务器地址:
    https://login.sina.com.cn/cgi/pin.php?r=18674039&s=0&p=yf-c92f2edb50c21d4bcbfdc3fccfdb94c4c23f
    其中分析后发现:
    固定服务器url:https://login.sina.com.cn/cgi/pin.php?
    携带的参数:r = 18674039,p = yf-c92f2edb50c21d4bcbfdc3fccfdb94c4c23f,s = 0
    其中s和p是固定值,r是一串不固定变化的数字,在分析的过程中,我试图寻找关于r的规律,最后实在没办法,我打算在Fiddler中测试一下,看看不加参数r是否能获得,结果是可喜可贺的,确实获得了。
    事实上,在保证cookie一致的情况下,去请求验证码,也就是说和你本次的登录保持在一个cookie中,可以主动的抓取验证码。

    # 获取验证码
    def get_verificationcode():
        print("开始请求获取验证码...")
        url = "https://login.sina.com.cn/cgi/pin.php?s=0&p=yf-9f5e31626347e127bc21874aa9d6f4d745ca"
        request.urlretrieve(url=url, filename="./img/code.jpg")
        print("验证码获取成功!")
        return input("请输入验证码:")
    

    在应对验证码问题上,我这里采用的是半人工半自动的,将每次获得的验证码存到当前目录下的img文件中,人工查看和输入验证码。

    关于第一步,账号和密码加密

    经分析在第二步发送登录的post请求之前,浏览器会实现发一个请求,请求的响应信息如下:
    公钥
    里边携带的servertime、pubkey、nonce、rsakv等关键信息在后边加密密码和包装post请求数据非常关键。关于如何得到这个分析以及整个爬虫的结构也,参考了这篇博文:https://www.cnblogs.com/houkai/p/3488468.html.
    以下是加密模块encrypt.py的代码

    import base64
    import binascii
    import rsa
    
    # 对用户名加密
    def encryUsername(username):
        print("开始加密用户名...")
        text = (base64.b64encode(username.encode(encoding="utf-8")))
        text = text.decode()
        return str(text).replace("=", "")
    
    # 对密码加密
    def encryPassword(password,servertime,nonce,pubkey):
        print("开始加密密码...")
        rsaPublickey = int(pubkey, 16)
        key = rsa.PublicKey(rsaPublickey, 65537)  # 创建公钥
        message = str(servertime) + '\t' + str(nonce) + '\n' + str(password)  # 拼接明文js加密文件中得到
        message = bytes(message, encoding="utf-8")
        passwd = rsa.encrypt(message, key)  # 加密
        passwd = binascii.b2a_hex(passwd)  # 将加密信息转换为16进制。
        return passwd
    

    登录请求post数据包装

    在Chrome的开发者模式下,可以抓取相关参数信息

    # 组织post数据
    def get_postData(su,password,servertime,nonce,pubkey,rsakv):
        print("开始组织post数据...")
        # 密码加密
        sp = encrypt.encryPassword(password, servertime, nonce, pubkey)
        # 验证码请求
        door = get_verificationcode()
        # 构造post请求参数
        data = {
            "door": door,
            "entry": "weibo",
            "gateway": 1,
            "from": "",
            "savestate": 7,
            "su": su,
            "sp": sp,
            "servertime": servertime,
            "service": "miniblog",
            "nonce": nonce,
            "rsakv": rsakv,
            "encoding": "UTF-8",
            "domain": "sina.com.cn",
            "returntype": "META",
            "vsnf": 1,
            "useticket": 1,
            "pwencode": "rsa2",
            "prelt": 372,
            "qrcode_flag": "false",
            "url": "https://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack"
        }
        data = parse.urlencode(data).encode("utf-8")
        return data
    

    关于登录后如跳转到主页面

    这个过程参考了:https://www.cnblogs.com/woaixuexi9999/p/9404745.html
    在模块login.py中定义了一个类Login,其中的登录方法代码:

        def login(self):
            # 第一步  获得时间戳、公钥、nonce等数据
            req = request.Request(url=self.__preloginUrl,headers=self.headers1,method="get")
            response = request.urlopen(req)
            text = response.read()
            servertime, nonce, pubkey, rsakv = dealdata.get_prelogin(text=text)
    
            # 第二步 向服务器发送post请求 登录信息
            postdata = dealdata.get_postData(self.__su,self.__password,servertime,nonce,pubkey,rsakv)
            req = request.Request(url=self.__loginUrl, headers=self.__postheaders, data=postdata,method="post")
            response = request.urlopen(req)
            text = response.read()
    
            # 第三步 解析登录响应数据 获取中间链接
            replaceUrl = dealdata.get_replaceUrl(text=text)
    
            # 分析登录结果
            result,retcode,reason = dealdata.get_reason(replaceUrl)
            if result==False:
                print("登录失败!")
                print("原因",reason)
                return
            else:
                print("登录成功!")
                print("正在向个人主页跳转...")
    
            # 第四步 加载中间链接 提取ticket
            response = request.urlopen(replaceUrl)
            text = response.read()
            ticket = dealdata.get_ticket(text=text)
    
            # 第五步 利用ticket组合关键部分构造网址 获得携带uniqueid的json数据
            uniqueidUrl = ticket + "&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript0&client=ssologin.js(v1.4.19)&_=1564805281285"
            response = request.urlopen(uniqueidUrl)
            text = response.read()
            uniqueid = dealdata.get_uniqueid(text)
    
            # 第六步 跳转到主页
            print("进入个人主页...")
            homeUrl = "https://weibo.com/u/" + uniqueid + "/home"
            request.urlretrieve(homeUrl, "./html/home.html")
    

    其他模块

    处理数据的dealdata.py模块

    dealdata模块
    工程文件列表
    文件列表
    code.jpg是验证码
    home.html是加载的主页

    执行结果

    运行结果

    初学Python,深感Python的强大。人生苦短,我用Python。
    此程序仅供尝试使用,不可商用。
    转载请注明出处:https://blog.csdn.net/Blz624613442/article/details/98368815

    展开全文
  • Python3爬虫登录模拟

    2017-10-24 23:10:25
    使用Python爬虫登录系统之后,能够实现的操作就多了很多,下面大致介绍下如何使用Python模拟登录。 我们都知道,在前端的加密验证,只要把将加密环境还原出来,便能够很轻易地登录。 首先分析登录的步骤,通过审查...

    使用Python爬虫登录系统之后,能够实现的操作就多了很多,下面大致介绍下如何使用Python模拟登录。

    我们都知道,在前端的加密验证,只要把将加密环境还原出来,便能够很轻易地登录。

    首先分析登录的步骤,通过审查元素得知

    <input type="button" id="login" name="login" class="login" onclick="Logon();" value="登录">

    点击按钮触发Logon()函数,然后查找Logon()函数定义

    function Logon() {
    }

    函数定义内容各有不同,一般里面包含一些加密的操作,一般是使用写好的js加密。我们所需要做的便是重复这些步骤,加密数据。

    对于加密,有三种方法:

    第一,如果加密方法是base64之类的,可以直接用Python3的base64库加密;

    第二,手动模仿;

    第三,直接调用js加密,需要先下载PyExecJS,有的电脑需要先安装js的运行环境,比如Node.js。使用方法如下:

    newusername = execjs.compile(content).call('base64encode', username)

    其中content是js内容,base64encode是方法,username是参数,newusername是加密后的数据。

    对于验证码的问题,先介绍下一般的图片验证码,可以请求获取验证码的地址,session之类的数据自己搞定,一般便可以请求成功,可以存到本地手动输入,也可以使用识别的第三方模块,但这个识别效果并不是很好。

    然后,便是查看session,cookie。

    接下来的操作就是构造请求头headers,这个可以自行去控制台查看或者使用wireshark, fiddler之类的抓包软件查看。

    最后便可以请求数据:

    使用

     s = requests.Session()
     s.headers.update(headers)
     r = s.post(url, data = params)

    或者:

      r = requests.get(url, headers = headers, data = params)

    headers是你构造的请求头,url是你请求的网站,params是加密的数据。

    展开全文
  • 先附上源代码,随后得空再把开发思路附上 python_login_wiebops:在这吐槽下csdn的上传功能,传了3,4次没成功,我也是醉了
  • 专业的术语,总是让我们听得云里雾里,但是总的来说,大家应该都知道爬虫的基本流程吧,首先是将自己进行伪装,跟一个正常的登录使用人员一样,但是最终,别人只是看一遍知识,而我们是需要进行知识的获取的,这也就...
  • python爬虫模拟登录 这里我们讲解一下,python爬虫必备的模拟登录技能,通过下面的课程希望你们能了解析python爬虫模拟登录机制与实现原理 阅读目录python爬虫模拟登录前言一、pyhton模拟登录原理二、分析...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 299
精华内容 119
关键字:

python3爬虫模拟登录

python 订阅
爬虫 订阅