第三次实践

作业①

要求:

指定一个网站,爬取这个网站中的所有的所有图片,例如中国气象网(http://www.weather.com.cn)。分别使用单线程和多线程的方式爬取。(限定爬取图片数量为学号后3位)

输出信息:

将下载的Url信息在控制台输出,并将下载的图片存储在images子文件夹中,并给出截图。

爬取中国气象网网页所有图片

观察网页,发现图片还能点击跳转到详细图片界面


观察f12中的详细地址url,得到图片网站urls的规律:

urls = re.findall(r'href="(.*?shtml)"',html)

对每个url,用正则匹配对爬取到的网页内容进行匹配找到.jpg图片地址

pics = re.findall(r'img class="lunboimgages" src="(.*?jpg)"',htmls)

将得到的图片保存

pic_url = pics[j]
response = urllib.request.urlopen(pic_url)
c_img = response.read()
c_name = str(k) + '.jpg'
with open(c_name, 'wb') as f:
    f.write(c_img)

运行结果:(单线程)

多线程实现:

定义一个下载函数

def download(url,num):
    response = urllib.request.urlopen(url)
    bag_img = response.read()
    bag_name = str(num) + '.jpg'
    with open(bag_name,'wb') as f:
        f.write(bag_img)
    s = "第" + str(num) + "张图片爬取完成;"
    print(s)

将下载加入多线程中

T = threading.Thread(target=download, args=(pic_url, k))
T.setDaemon(False)
T.start()
threads.append(T)

for t in threads:
    t.join()

运行结果:(多线程)

Gitee地址:

作业一:
单线程:https://gitee.com/flyme10086/data-excavate/blob/master/作业3/任务一/weather_pic.py
多线程:https://gitee.com/flyme10086/data-excavate/blob/master/作业3/任务一/weather_pics.py

心得体会:

此实验进一步锻炼了我对多线程的理解和使用,通过此实验,我还更进一步了解熟悉了正则匹配、网页的跳转翻页等操作。

作业②

要求:

使用scrapy框架复现作业①。

输出信息:

同作业①

创建scrapy项目并进入项目目录

scrapy startproject weather
#成功执行上述命令后,进入weather这个项目目录
cd weather

创建爬虫文件

scrapy genspider -t basic wpic weather.com

用pycharm打开项目文件夹,进行修改

items.py

pic_url = scrapy.Field()

settings.py

#忽略网站爬虫协议
ROBOTSTXT_OBEY = False
#配置piplines.py能够使用
ITEM_PIPELINES = {
    'weather.pipelines.WeatherPipeline': 300,
}
#配置保存图片的目录(若无此目录自动创建)
IMAGES_STORE = './pic'

新建run.py

from scrapy import cmdline
#不用切换命令提示符,直接运行run.py
cmdline.execute("scrapy crawl wpic".split())

编写爬虫文件wpic.py

#设置开始url
start_urls = ['http://p.weather.com.cn/txqg/index.shtml']
#实现进入图片详细页
def parse(self, response):
    urls = response.xpath('//div[@class="tu"]/a/@href').extract()
    for url in urls:
        yield scrapy.Request(url=url, callback=self.img_parse)
#实现每一页图片爬取
def img_parse(self,response):
    item = WeatherItem()
    item["pic_url"] = response.xpath('//div[@class="buttons"]/span/img/@src').extract()
    yield item

编写piplines.py

from scrapy.pipelines.images import ImagesPipeline
#继承ImagesPipeline类
class WeatherPipeline(ImagesPipeline):
    def get_media_requests(self,item,info):
        for i in range(len(item['pic_url'])):
            yield scrapy.Request(url=item['pic_url'][i])
    def item_completed(self, results, item, info):
        # 返回item给下一个管道对象
        return item
    # 自定义一个__del__方法(方便最后执行!)
    def __del__(self):
        print('已全部下完毕!')

运行结果:

Gitee地址:

作业二:
https://gitee.com/flyme10086/data-excavate/tree/master/作业3/任务二

心得体会:

本次作业与之前几次不同的地方在于:使用scrapy框架实现翻页及图片的下载,通过此次实验,我对scrapy的使用有了进一步了解。

作业③

要求:

爬取豆瓣电影数据使用scrapy和xpath,并将内容存储到数据库,同时将图片存储在imgs路径下。

候选网站

https://movie.douban.com/top250

输出信息:

序号 电影名称 导演 演员 简介 电影评分 电影封面
1 肖申克的救赎 弗兰克·德拉邦特 蒂姆·罗宾斯 希望让人自由 9.7 ./imgs/xsk.jpg
2....

创建scrapy项目并进入项目目录

scrapy startproject douban
#成功执行上述命令后,进入weather这个项目目录
cd douban

创建爬虫文件

scrapy genspider -t basic db douban.com

用pycharm打开项目文件夹,进行修改

items.py

num = scrapy.Field()
name = scrapy.Field()
roles = scrapy.Field()
introduce = scrapy.Field()
star = scrapy.Field()
pic = scrapy.Field()

settings.py

#忽略网站爬虫协议
ROBOTSTXT_OBEY = False
#伪装浏览器访问
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36',
}
#配置piplines.py能够使用
ITEM_PIPELINES = {
    'douban.pipelines.DoubanPipeline': 300,#保存至数据库
    'douban.pipelines.PicPipeline': 800,#保存电影封面图片
}
#配置保存图片的目录(若无此目录自动创建)
IMAGES_STORE = './imgs'

新建run.py

from scrapy import cmdline
#不用切换命令提示符,直接运行run.py
cmdline.execute("scrapy crawl db ".split())

编写爬虫文件db.py

运用xpath匹配获取网页信息,并将其存入数据库中,电影封面图片保存至本地

#设置开始url
start_urls = ['https://movie.douban.com/top250']
#xpath获取详细信息
item = DoubanItem()
item["num"] = response.xpath("//ol/li/div/div/em/text()").extract()
item["name"] = response.xpath("//ol/li/div/div/a/img/@alt").extract()
infos = response.xpath('//div[@class="bd"]/p[1]/text()')
item["roles"] = [j for i, j in enumerate(infos) if i % 2 == 0]
item["introduce"] = response.xpath("//ol/li/div/div/div/p/span/text()").extract()
item["star"] = response.xpath('//ol/li/div/div/div/div/span[@class="rating_num"]/text()').extract()
        item["pic"] = response.xpath("//ol/li/div/div/a/img/@src").extract()
#实现翻页爬取
for i in range(1,10): #翻页操作
    s = i * 25
    time.sleep(random.random() * 3)
    url = 'https://movie.douban.com/top250?start=' + str(s) + '&filter='
    yield scrapy.Request(url, callback=self.parse)

编写piplines.py

实现数据库的打开、关闭和插入数据的方法

class MovieDB:
    #打开数据库的方法
    def openDB(self):
        self.con=sqlite3.connect("movies.db")
        self.cursor=self.con.cursor()
        self.cursor.execute("create table if not exists movies (mNum char(16),mName char(128),mDirect char(128),mActor char(128),mIntroduce char(128),mStar char(16),mPic char(256),constraint pk_movie primary key (mName))")
    #关闭数据库的方法
    def closeDB(self):
        self.con.commit()
        self.con.close()
    #插入数据的方法
    def insert(self, num, name, direct, actor, introduce, star, pic):
        try:
            self.cursor.execute("insert into movies (mNum, mName, mDirect, mActor, mIntroduce, mStar, mPic) values (?,?,?,?,?,?,?)",(num, name, direct, actor, introduce, star, pic))
        except Exception as err:
            print(err)

电影信息保存至数据库

class DoubanPipeline():#保存至数据库
    def process_item(self, item, spider):
        self.db = MovieDB()
        self.db.openDB()
        for i in range(len(item["num"])):
            directs = re.findall(r'导演: (.*?)\xa0',item["roles"][i].extract())
            actors = re.findall(r'主演: (.*?)[\./]',item["roles"][i].extract())
            #避免因为为空而插入数据库报错IndexError: list index out of range
            try:
                direct = directs[0]
                actor = actors[0]
            except:
                direct = " "
                actor = " "
            self.db.insert(item["num"][i], item["name"][i], direct, actor, item["introduce"][i], item["star"][i], item["pic"][i])
        self.db.closeDB()
        return item

图片保存至本地(和作业二类似)

class PicPipeline(ImagesPipeline):#保存电影封面图片
    def get_media_requests(self,item,info):
        for i in range(len(item['pic'])):
            yield scrapy.Request(url=item['pic'][i])

    def item_completed(self, results, item, info):
        # 返回item给下一个管道对象
        return item

运行结果:

Gitee地址:

作业三:
https://gitee.com/flyme10086/data-excavate/tree/master/作业3/任务三

心得体会:

本次作业要求我们进一步掌握scrapy框架的使用。通过此次实验,我对scrapy的使用有了更深的体会和认识。

遇到的问题:

豆瓣源码中,导演与主演存放在同一个标签下,xpath无法直接分别读取。同时豆瓣存在部分电影预览界面因为导演名字过长,网页源码中只有导演而无主演,从而导致直接使用正则匹配时爬取到的主演列表数量缺少,与其他条目无法对应。

解决方法:

将整条导演与主演存放进item["roles"],在pipelines.py文件中再分割出导演与主演。

posted @ 2021-10-27 21:57  Flyme10086  阅读(49)  评论(0编辑  收藏  举报