作业①

1)实验要求

  • 指定一个网站,爬取这个网站中的所有的所有图片,例如中国气象网(http://www.we ather.com.cn)。分别使用单线程和多线程的方式爬取。
  • 输出信息:将下载的Url信息在控制台输出,并将下载的图片存储在images子文件中,并给出截图。

2)思路分析

分析网页,发现对应翻页信息

数据采集作业三_数据库

 获取href的正则表达式为:

href = re.findall(r'<a href="(.+?)"', r)

再分析网页,找到需要获取的图片信息 发现存在img的src中

数据采集作业三_数据库_02

 然后就可以开始写代码啦

单线程:

获取网页信息,为了翻页做准备

def getHTML(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

翻页处理模块

for i in range(len(href)):
    rsp = href[i].strip()
    imageSpider(rsp)
    #爬取中途会出现报错
    if rsp == 'javascript:void(0)':
        continue

下载图片模块

def download(url):
    global count
    try:
        count += 1
        #学号尾号是131
        if count<=131:
            if (url[len(url) - 4] == "."):
                ext = url[len(url) - 4:]
            else:
                ext = ""
            req = urllib.request.Request(url, headers=headers)
            data = urllib.request.urlopen(req, timeout=100)
            data = data.read()
            # 将下载的图像文件写入本地文件夹
            fobj = open("D:\\数据采集\\images\\" + str(count) + ext, "wb")
            fobj.write(data)
            fobj.close()
            print(url)
            print("download " + str(count) + ext)
    except Exception as err:
        print(err)

输出结果(顺序输出)数据采集作业三_数据采集_03

数据采集作业三_数据采集_04

 多线程:

与单线程想比,需要添加的内容

if url not in urls:
    print(url)
    count = count + 1
    # 创建线程
    T = threading.Thread(target=download, args=(url, count))
    T.setDaemon(False)
    T.start()
    threads.append(T)
for i in range(len(href)):
    rsp = href[i].strip()
    imageSpider(rsp)
    #多线程
    for t in threads:
        t.join()
    if rsp == 'javascript:void(0)':
        continue

输出结果(非顺序)

数据采集作业三_多线程_05

数据采集作业三_数据采集_06

 3)心得体会

单线程和多线程的练习之前也有做过,这次主要是翻页处理比较难,找到href以后一开始也没想到怎么处理。然后最开始翻页处理的时候,图片下载到104张就停止了,但是尝试输出rsp以后,后面的rsp可以输出,中间会跳出javascript:void(0)无法识别的错误,去掉以后就正常了。

 

作业

1)实验要求

  • 使用scrapy框架复现作业①
  • 输出信息:同作业①

2)思路分析

网页分析之前以后做过了,改写用scrapy框架就好了

items:

class WeatherdemoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img = scrapy.Field()

myweatherSpider:

class MYweatherSpider(scrapy.Spider):
    name = 'weather'
    allowed_domains = ['weather.com']
    url='http://www.weather.com.cn/'
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    href = re.findall(r'<a href="(.+?)"', str(r))

    def start_requests(self):
        yield scrapy.Request(url=MYweatherSpider.url, callback=self.parse)

    def parse(self, response):
        count=0
        selector = Selector(text=response.text)
        srclist = selector.xpath("//img/@src").extract()
        for src in srclist:
            if count <131:
                item = WeatherdemoItem()
                print("src", src)
                item['img'] = src
                count + 1
                yield item
        if count <131:
            yield scrapy.Request(url=MYweatherSpider.href, callback=self.parse)

pipelines:

class WeatherdemoPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        yield scrapy.Request(item['img'])

    def file_path(self, request, response=None, info=None):
        imgname = request.url.split("/")[-1]
        return imgname

    def item_completed(self, results, item, info):
        return item    #返回给下一个即将被执行的管道类

settings:

USER_AGENT ='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.40'
#增加访问header,加个降低被拒绝的保险
ITEM_PIPELINES ={
    'weatherdemo.pipelines.WeatherdemoPipeline':1
}
IMAGES_STORE = 'D:/数据采集/images'#图片保存地址
BOT_NAME = 'weatherdemo'

SPIDER_MODULES = ['weatherdemo.spiders']
NEWSPIDER_MODULE = 'weatherdemo.spiders'
LOG_LEVEL='ERROR'

run:

from scrapy import cmdline

cmdline.execute("scrapy crawl weather ".split())

输出结果

数据采集作业三_ide_07

数据采集作业三_单线程_08

 3)心得体会

最开始写scrapy框架的时候有点懵,不知道哪个py文件写哪个内容,经常跑出来是一片红色,后来发先是item[img]那里写错了,总的来说也让我对scrapy框架更加熟悉了。

 

作业③

1)实验要求

  • 要求:爬取豆瓣电影数据使用scrapy和xpath,并将内容存储到数据库,同时将图片存储在imgs路径下。
  • 候选网站: https://movie.douban.com/top250
  • 输出信息:
序号 电影名称 导演 演员 简介 电影评分 电影封面
1 肖申克的救赎 弗兰克·德拉邦特 蒂姆·罗宾斯 希望让人自由 9.7 ./imgs/xsk.jpg
2 ...          

2)思路分析

分析网页获取信息

数据采集作业三_数据采集_09

 发现导演和演员连在了一起,要想办法分开,编写的xpath代码如下

item['raking'] = li.xpath(".//em/text()").extract_first()  # 序号
item['name']=li.xpath(".//div[@class='info']//a/span[@class='title']/text()").extract_first()  # 电影名称
act = li.xpath(".//div[@class='bd']/p/text()").extract_first()  # 导演和演员
acts = act.split("主演:")
try:
    item['director'] = re.search(':.*:', acts).group()[1:-3]
except:
    item['director'] = "奥利维·那卡什 Olivier Nakache / 艾力克·托兰达 Eric Toledano "
item['actor'] = acts[0].split(':')[1]
item['content']=li.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").extract_first()  # 简介
item['number']=li.xpath(".//div[@class='star']/span[@class='rating_num']/text()").extract_first()  # 电影评分
item['img']= li.xpath(".//div/a/img/@src").extract_first()  # 电影封面

翻页规律

https://movie.douban.com/top250

https://movie.douban.com/top250?start=25&filter=

https://movie.douban.com/top250?start=50&filter=

start_url = 'https://movie.douban.com/top250'
url = MymovieSpider.start_url + "?start=" + str(i *25)

items:

class MoviedemoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    raking = scrapy.Field()  # 排名
    name = scrapy.Field()  # 电影名称
    director = scrapy.Field()  # 导演
    actor = scrapy.Field()  # 演员
    content = scrapy.Field()  # 简介
    number = scrapy.Field()  # 评分
    img = scrapy.Field()  # 封面

pipelines:

数据库(之前实验有写过,算是复习)

class movieDB:
    # 打开数据库的方法
    def openDB(self):
        self.con = sqlite3.connect("movie.db")
        self.cursor = self.con.cursor()
        try:
            self.cursor.execute(
                "create table movies(raking varchar(5),name varchar(16),director varchar(20),actor varchar(20),content varchar(20),score varchar(5),picture varchar(16) )" )
        except:
            self.cursor.execute("delete from movies")

    def closeDB(self):
        self.con.commit()
        self.con.close()
    # 加入元组
    def insert(self, raking, name, director, actor, content, score, picture):
        try:
            self.cursor.execute("insert into movies (raking, name, director, actor, content, score, picture) "
                                "values (?,?,?,?,?,?,?)",
                                (raking, name, director, actor, content, score, picture))
            # 插入表
        except Exception as err:
            print(err)

插入数据并下载图片

    def process_item(self, item, spider):
        self.db.insert(item["raking"], item["name"], item["director"], item["actor"], item["content"], item["number"],
                       item["img"])
        urllib.request.urlretrieve(item["img"], 'D:\数据采集\images\\' + str(item["raking"]) + '.jpg')
        try:
            print(item["raking"])
            print(item["name"])
            print(item["director"])
            print(item["actor"])
            print(item["content"])
            print(item["number"])
            print(item["img"])
        except Exception as err:
            print(err)
        return item

settings:

ITEM_PIPELINES = {
    'moviedemo.pipelines.MoviedemoPipeline': 300,
}

run:

from scrapy import cmdline

cmdline.execute("scrapy crawl mySpider".split())

输出内容

数据采集作业三_单线程_10

数据采集作业三_单线程_11

 3)心得体会

这个实验改了很久很久很久,报错都是一片红,最印象深刻的两个点是 start_url要去掉列表,以及在区分导演和演员时列表没法切割。总之还是要多加练习呀。

 

 

代码地址:

moocy: 是cyy的代码呀 - Gitee.com