zoukankan      html  css  js  c++  java
  • 爬虫第六次作业

    作业①:

    要求:
        用requests和BeautifulSoup库方法爬取豆瓣电影Top250数据。
        每部电影的图片,采用多线程的方法爬取,图片名字为电影名
        了解正则的使用方法
    
    from bs4 import BeautifulSoup
    from bs4 import UnicodeDammit
    import urllib.request
    import threading
    import re
    def imageSpider(start_url):#图片爬取
        global count  # 全局变量,设置这个完全是因为想名称给解决哈哈!
        global threads
        try:
            urls = [] #最终所要得到爬取图片的网址一开始会置为空
            req = urllib.request.Request(start_url, headers=headers) #引入全局变量headers改换头部信息实现多次爬取
            data = urllib.request.urlopen(req) #目标网址打开
            data = data.read() #对网站内容进行读操作
            dammit = UnicodeDammit(data, ["utf-8", "gbk"])#用utf-8和gbk来猜测文本编码,从而设置函数最终信息编码标准
            data = dammit.unicode_markup #将内容可转化为text
            soup = BeautifulSoup(data, "lxml") #用lxml来解析
            images = soup.select("img")#选取我们的目标(图片)的tag
            for image in images:#images是存储所有的图片,而image是存取单个图片(可替换)
                src = image["src"]#src存储的是图片的名称
                url = urllib.request.urljoin(start_url, src)#urljoin构建绝对路径
                if url not in urls:#将每一次获取得到的新的单个网址存入urls里面 避免重复
                    count = count+1
                    T = threading.Thread(target=download,args=(url,count))# 单个线程的执行操作,执行目标函数download(url,count)4
                    T.setDaemon(False) #确保所有的线程都已经执行完毕(后台线程不会随主线程结束而结束)
                    T.start() #开始执行
                    threads.append(T) #将该线程归为线程池,确保后续的所有线程都已经完成
                    #print(url)#打印已经下载的图片
        except Exception as er:
            print(er)
    
    
    def download(url,count):#具体的下载过程
        try:
            count = count + 1#我是选择一开始就加一
            if (url[len(url) - 4] == "."):#判断是否为目标文件(图片)
                ext = url[len(url) - 4:]#获取图片的格式jdp还是png
            else:
                ext = ""
            req = urllib.request.Request(url, headers=headers)#可以更有效的多次爬虫
            data = urllib.request.urlopen(req, timeout=100)#防止超时,和第一个函数比有相同的部分,这个就不太好重复工作
            data = data.read()#进行图片的数据读
            fobj = open("images\" + str(count) + ext, "wb")#默认是在编译器存储在同一个文档中,命名形式用count的具体指哈哈,根据读取的格式来结尾,允许读写图片
            fobj.write(data)#写数据
            fobj.close()#最后要关闭这个进程
        except Exception as e:
            print(e)
    
    def doubanSpider(start_url):#数据爬取
        try:
            req = urllib.request.Request(start_url, headers=headers)  # 引入全局变量headers改换头部信息实现多次爬取
            data = urllib.request.urlopen(req)  # 目标网址打开
            data = data.read()  # 对网站内容进行读操作
            print("排名","电影名称 ","导演 ","主演","上映时间","国家","电影类型","评分","评价人数 ","引用" ,"文件路径", chr(12288))  # 采用中文字符的空格填充chr(12288)
            dammit = UnicodeDammit(data, ["utf-8", "gbk"])#用utf-8和gbk来猜测文本编码,从而设置函数最终信息编码标准
            data = dammit.unicode_markup #将内容可转化为text
            soup = BeautifulSoup(data, "lxml")
            #用lxml来解析
            lis = soup.select('ol[class="grid_view"] li')#选取我们的目标(图片)的tag
            for li in lis:
                rank=li.select('div[class="pic"] em[class=""]')[0].text.replace("em",'').replace("
    ",'')#排名
                fn=li.select('div[class="info"] div a span ')[0].text.replace("span",'').replace("
    ",'')#电影名称
                info_l=li.select('div[class="bd"] p')[0].text.replace("p",'').replace("
    ",'').replace(" ",'')#信息人员
                info_f =li.select('div[class="bd"] br')[0].text.replace("br",'').replace("
    ",'').replace(" ",'')#电影信息
                comment=li.select('div[class="bd"] div[class="star"] span[class="rating_num"]')[0].text.replace("span",'').replace("
    ",'').replace(" ",'')#评价信息
                audi=li.select('div[class="star"] span')[3].text.replace("span",'').replace("
    ",'').replace(" ",'')#观影
                refer=li.select('div[class="bd"] p[class="quote"]')[0].text.replace("p",'').replace("
    ",'').replace(" ",'')#引用
                file=str(rank)+".jpg"
                print(rank,fn,info_l,info_f,comment,audi,refer,file)
        except Exception as er:
            print(er)
    
    
    start_url = "https://movie.douban.com/top250"#目标网站豆瓣
    headers = {
        "User-Agent": "Mozilla/5.0(Windows;U;Windows NT 6.0 x64;en-US;rv:1.9pre)Gecko/2008072421 Minefield/3.0.2pre"}
    count = 0
    threads = [] #线程池
    imageSpider(start_url) # 调用函数
    for t in threads:
        t.join() #等待其他线程完成
    doubanSpider(start_url)
    print("over!")
    


    心得体会:

    多多调试,题目具有一定的灵活性;
    没做之前觉得挺难的,做完后觉得还可以,是在自己力所能及的范围内;
    任务分为两步:图片下载和数据爬取;
    也发现自己的不足:知识有些遗忘,但也还好吧!之前动手实践过,所以还行

    作业②:

    要求:
        熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;Scrapy+Xpath+MySQL数据库存储技术路线爬取科软排名信息
        爬取科软学校排名,并获取学校的详细链接,进入下载学校Logo存储、获取官网Url、院校信息等内容。
    

    rankank.py

    import scrapy
    from ..items import RankItem
    from bs4 import BeautifulSoup
    import urllib.request
    from bs4 import UnicodeDammit
    """
    第六次作业
    """
    # -*- coding: utf-8 -*-
    class RankankSpider(scrapy.Spider):
        name = 'rankank'
        start_url = 'https://www.shanghairanking.cn/rankings/bcur/2020'
        def start_requests(self):
            url = RankankSpider.start_url
            yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            dammit = UnicodeDammit(response.body, ["utf-8", "gdk"])
            data = dammit.unicode_markup
            selector = scrapy.Selector(text=data)
            lis =selector.xpath("//div[@class='rk-table-box']/table/tbody/tr")
            count=0
            for li in lis:
                #下面为每一所大学的信息爬取
                sno =  li.xpath("./td[position()=1]/text()").extract_first() # 排名
                sno=str(sno).strip()
                sname = li.xpath("./td[@class='align-left']/a/text()").extract_first()  # 名字
                sname = str(sname).strip()
                scity = li.xpath("./td[position()=3]/text()").extract_first()  # 城市
                scity = str(scity).strip()
                surl =  li.xpath("./td[@class='align-left']/a//@href").extract() # url
                surl = str(surl).strip().replace("[",'').replace("'",'').replace("]",'')
                sfile = str(count) + ".png"  # 文件
                ##
                se_url = response.urljoin(surl)
                headers = {
                    "User-Agent": "Mozilla/5.0(Windows;U;Windows NT 6.0 x64;en-US;rv:1.9pre)Gecko/2008072421 Minefield/3.0.2pre"}
                req = urllib.request.Request(se_url, headers=headers)  # 引入全局变量headers改换头部信息实现多次爬取
                data1 = urllib.request.urlopen(req)  # 目标网址打开
                data1 = data1.read()  # 对网站内容进行读操作
                #进而提取出图片信息与文字信息
                dammit = UnicodeDammit(data1, ["utf-8", "gbk"])  # 用utf-8和gbk来猜测文本编码,从而设置函数最终信息编码标准
                data1 = dammit.unicode_markup
                soup1 = BeautifulSoup(data1, "lxml")  # 用lxml来解析
                # 获取信息
                info = soup1.select('div[class="univ-introduce"] p')[0].text.replace("p",'')
                sinfo = info  # 信息
                sinfo = str(sinfo).strip()
                #获取图片
                images = soup1.select('td[class="univ-logo"] img')  # 选取我们的目标(图片)的tag,由于为所有图片所以之后要for
                for image in images:  # images是存储所有的图片,而image是存取单个图片(可替换)
                    url = image["src"]  # src存储的是图片的名称
                if (url[len(url) - 4] == "."):  # 判断是否为目标文件(图片)
                    ext = url[len(url) - 4:]  # 获取图片的格式jdp还是png
                else:
                    ext = ""
                req = urllib.request.Request(url, headers=headers)  # 可以更有效的多次爬虫
                data2 = urllib.request.urlopen(req, timeout=100)  # 防止超时,和第一个函数比有相同的部分,这个就不太好重复工作
                data2 = data2.read()  # 进行图片的数据读
                fobj = open("images\" + str(count) + ext, "wb")  # 默认是在编译器存储在同一个文档中,命名形式用count的具体指哈哈,根据读取的格式来结尾,允许读写图片
                count = count + 1
                fobj.write(data2)  # 写数据
                fobj.close()  # 最后要关闭这个进程
                item = RankItem()
                item["sno"] = sno
                item["sname"] = sname
                item["scity"] = scity
                item["surl"] = surl
                item["sinfo"] = sinfo
                item["sfile"] = sfile
                yield item
            pass
    

    pipeline.py

    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    
    
    # useful for handling different item types with a single interface
    from itemadapter import ItemAdapter
    import pymysql
    
    class RankPipeline:
        def open_spider(self, spider):
            print("opened")
            try:
                self.con = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="20201006Wu", db="rankank",
                                           charset="utf8")  # 链接数据库,db要是自己建的数据库
                self.cursor = self.con.cursor(pymysql.cursors.DictCursor)
                self.cursor.execute("delete from rankank")  # 删除表格的原来内容
                self.opened = True  # 执行打开数据库
            except Exception as error:
                print(error)
                self.opened = False  # 不执行打开数据库
        def process_item(self, item, spider):
            try:
                print(item["sno"],item["sname"], item["scity"], item["surl"], item["sinfo"], item["sfile"])#控制端输出信息
                if self.opened:
                    self.cursor.execute(
                        "insert into rankank(sno,sname,scity,surl,sinfo,sfile)values(%s,%s,%s,%s,%s,%s)",
                        (item["sno"],item["sname"], item["scity"], item["surl"], item["sinfo"], item["sfile"]))
                    #插入sql语句
            except Exception as e:
                print(e)
            return item
    
        def close_spider(self, spider):
            if self.opened:
                self.con.commit()
                self.con.close()
                self.opened = False
                print("closed")
    

    items.py

    # Define here the models for your scraped items
    #
    # See documentation in:
    # https://docs.scrapy.org/en/latest/topics/items.html
    import scrapy
    class RankItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        sno=scrapy.Field()#排名
        sname = scrapy.Field()#名字
        scity = scrapy.Field()#城市
        surl = scrapy.Field()#url
        sinfo = scrapy.Field()#信息
        sfile = scrapy.Field()#文件
        pass
    

    run.py

    from scrapy import cmdline
    cmdline.execute("scrapy crawl rankank -s LOG_ENABLED=False".split())
    

    settings.py

    BOT_NAME = 'rank'
    SPIDER_MODULES = ['rank.spiders']
    NEWSPIDER_MODULE = 'rank.spiders'
    ROBOTSTXT_OBEY = False
    ITEM_PIPELINES = {
        'rank.pipelines.RankPipeline': 300,
    }
    





    心得体会:

    不是特别难和上题一样,具有一定的灵活性;
    任务分为三个:图片下载,数据爬取,连接数据库;
    是上一题的进阶版>o<

    作业③:

    要求:
        熟练掌握 Selenium 查找HTML元素、爬取Ajax网页数据、等待HTML元素加载、网页跳转等内容。
        使用Selenium框架+ MySQL数据库存储技术模拟登录慕课网,并获取学生自己账户中已学课程的信息并保存在MYSQL中。
        其中模拟登录账号环节需要录制gif图。
    
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    import urllib.request
    import threading
    import sqlite3
    import os
    import datetime
    from selenium.webdriver.common.keys import Keys
    import time
    class icourse:
        header = {
            "User-Agent": "Mozilla/5.0(Windows;U;Windows NT 6.0 x64;en-US;rv:1.9pre)Gecko/2008072531 Minefield/3.0.2pre"
        }
        #这个恒定不变的!
        def start(self, url):#开始只需要利用url模拟浏览器搜索爬取
            chrome_options = Options()#调用chrome的浏览器
            chrome_options.add_argument("——headless")
            chrome_options.add_argument("——disable-gpu")
            self.driver = webdriver.Chrome(chrome_options=chrome_options)
            self.id=0#编号
            try:
                self.con = sqlite3.connect("icourse.db")
                #链接到指定数据库,事实证明是是运行的文件的下面的直接建立,额外再补充一下:这里的数据库也是表格
                self.cursor = self.con.cursor()
                try:
                    self.cursor.execute("drop table icourse")
                    #初始操作删除stock的数据库的原来所有内容
                except:
                    pass#报错直接忽略
                try:
                    sql = "create table icourse(id varchar(16) ,course varchar(64),college varchar(64),teacher varchar(64),team varchar(256),count varchar(256),process varchar(128),brief varchar(512))"
                    #所以我们只需要建一个数据库具体的表的为这句语句实现,指定为stock的表
                    self.cursor.execute(sql)
                    #表示执行上面的语句
                except:
                    pass#报错直接忽略
            except Exception as err:
                print("start")#报错显示其原因
            theurl='https://www.icourse163.org/'
            self.driver.get(theurl)  # 浏览器得到地
    ##嘻嘻我还是有办法找到简单的方法,就是先模拟登录通过theurl,
    ##完成登录后在跳转到指定的网站把信息爬取下来
        def closeUp(self):#关闭数据库与浏览器
            #这个部分和第一题是一样的
            try:
                self.con.commit()
                self.con.close()#数据库关闭
                self.driver.close()#浏览器关闭
            except Exception as err:
                print("close")#报错显示其原因
    
        def insertDB(self, id,course,college,teacher,team,count,process,brief):
            #将从浏览器爬取得到的数据插入数据库
            try:
                sql = "insert into icourse (id,course,college,teacher,team,count,process,brief) values (?,?,?,?,?,?,?,?)"
                #因为每次爬取的都是不同的数据,所以这个sql语句是含有参数的表示
                self.cursor.execute(sql, (id,course,college,teacher,team,count,process,brief))
                #执行sql指令
            except Exception as err:
                print("insert")#报错显示其原因
    
        def showDB(self):
            #实现在pycharm的控制台输出从浏览器导出到mysql结果
            try:
                con = sqlite3.connect("icourse.db")
                #第一步肯定是建立链接
                cursor = con.cursor()
                print("id","course","college","teacher","team","count","process","brief")#控制台显示的一排数据
                cursor.execute("select id,course,college,teacher,team,count,process,brief from icourse order by id")#sql语句获取数据
                #第二步执行mysql语句,得到的结果用rows暂存,所以之后我们还需要将rows分隔开打印
                rows = cursor.fetchall()
                for row in rows:
                    print(row[0], row[1], row[2], row[3], row[4],row[5], row[6], row[7])
                    #分隔开打印数据
                con.close()#读取完数据,关闭数据库
            except Exception as err:
                print("show")
    
        def execute(self, url):#在控制台输出正在进行的过程
            self.start(url)
            self.loginmooc()
            print("Starting")
            self.driver.get(url)  # 浏览器得到真正的网址地
            print("Processing")
            self.process()
            print("Closing")
            self.closeUp()
            print("Completed")
    
        def loginmooc(self):
            self.driver.maximize_window()#页面呈现为最大的形式
            self.driver.find_element_by_xpath("//a[@class='f-f0 navLoginBtn']").click()#选择登录|注册
            time.sleep(2)
            self.driver.find_element_by_xpath("//span[@class='ux-login-set-scan-code_ft_back']").click()#选择“其他方式”
            time.sleep(1.2)
            self.driver.find_elements_by_xpath("//ul[@class='ux-tabs-underline_hd']//li")[1].click()#在列表中选择“手机”
            time.sleep(0.3)
            iframe_id = self.driver.find_elements_by_tag_name("iframe")[1].get_attribute('id')
            self.driver.switch_to.frame(iframe_id)  
            #寻找下面的输入位置
            self.driver.find_element_by_xpath("//input[@id='phoneipt']").send_keys('18196534898')#
            time.sleep(3)
            self.driver.find_element_by_xpath("//input[@class='j-inputtext dlemail']").send_keys('$$$$$$$$$$$$')
            time.sleep(1.1)
            self.driver.find_element_by_xpath("//a[@class='u-loginbtn btncolor tabfocus ']").click()
            time.sleep(4.7)
            self.driver.get(self.driver.current_url)
    
        def process(self):#真正的爬取数据开始!
            time.sleep(1)
            try:
                lis = self.driver.find_elements_by_xpath("//div[@class='m-course-list']/div/div[@class]")
                #除图片以外其他所有信息均在这个目录下
                for li in lis:
                    self.id = self.id + 1
                    id=self.id
                    course= li.find_element_by_xpath(".//div[@class='t1 f-f0 f-cb first-row']").text#课程
                    college =li.find_element_by_xpath(".//a[@class='t21 f-fc9']").text#学院名
                    teacher=li.find_element_by_xpath(".//div[@class='t2 f-fc3 f-nowrp f-f0']/a[position()=2]").text#老师
                    team=li.find_element_by_xpath(".//div[@class='t2 f-fc3 f-nowrp f-f0']").text#所有的团队成员
                    count = li.find_element_by_xpath(".//span[@class='hot']").text#总人数数
                    brief = li.find_element_by_xpath(".//span[@class='p5 brief f-ib f-f0 f-cb']").text#课程的简介
                    process=li.find_element_by_xpath(".//span[@class='txt']").text#课程的时间进展
                    self.insertDB(id,course,college,teacher,team,count,process,brief )
                    time.sleep(1)
            except Exception as err:
                print("process")
    
    url = "https://www.icourse163.org/search.htm?search=%E8%89%BA%E6%9C%AF#/"#还是和上题同一个网址
    spider = icourse()
    icourse().execute(url)
    icourse().showDB()#没有()会报错因为self
    



    心得体会:

    不是特别难;
    任务分为三个:登录页面,爬取数据;
    对我而言,是上一次作业的进阶版
    但不得不提就是这行代码的重要性,不然会报错:
    selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//input[@id='phoneipt']"}
    (Session info: chrome=86.0.4240.198)
    代码:

    iframe_id = self.driver.find_elements_by_tag_name("iframe")[1].get_attribute('id')
    self.driver.switch_to.frame(iframe_id)
    #寻找下面的输入位置
    

    写一下这门课给我的感受:

    爬虫主要还是要动手实践,理论很多;
    实际操作会发现:没有预料的难;
    谢谢老师告诉爬取各种网页的方式,
    虽然在做实验的时候,觉得有些很繁琐,每次都要学习新的知识是`(>﹏<)′
    学的过程要保持一颗平淡的心,
    一步一步慢慢做,出现问题也不要过于急躁,总是有解决的方法!

  • 相关阅读:
    c#无边框窗体移动 屏蔽双击最大化
    怎么样让代码都带有注释?
    权限设置相关,利用Microsoft.Win32.Security
    计算几何常用算法概览[转]
    VS 常见快捷键
    关于读取txt文件的分段问题
    ajax 常用方法
    文件以附件形式下载的方法
    半角和全角互换
    在ubuntu 中安装 jsdoc
  • 原文地址:https://www.cnblogs.com/021800626-wyj/p/14033488.html
Copyright © 2011-2022 走看看