[数据采集]实验三

作业1

1.1题目

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

1.2实现过程

1.2.1 单线程爬取

if __name__ == "__main__":
	url = 'http://www.weather.com.cn/'
	picture_list = []			#用于记录得到的图片链接

	html = getHTMLText(url)
	pagelink = pagelinks(html)	# 找到其他页面跳转链接

	page = 8  # 学号031904138 爬取页数为8,图片数量为138
	for i in range(page):			#138=7*18+1*12  最后一页爬取12项
		url = pagelink[i]
		html = getHTMLText(url)		#爬取指定网页
		if(i==page-1):
			list = parsePage(html,12)	# 解析网页提取需要的数据,最后一页提取12项
		else:
			list = parsePage(html, 18)  # 解析网页提取需要的数据,提取前18项
		picture_list.extend(list)

	printGoodsList(picture_list)  # 打印得到的数据

	path = r"D:/第三次作业/picture/"	                #图片保存路径
	save2file(picture_list,path)			#将图片保存到本地文件

1.构造请求头并使用urllib.request爬取网页

# 使用urllib.request爬取网页
def getHTMLText(url):
	try:
		headers = {
			"user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
		}
		req = urllib.request.Request(url=url,headers=headers)
		data = urllib.request.urlopen(req)
		data = data.read()
		dammit = UnicodeDammit(data, ["utf-8", "gbk"])
		data=dammit.unicode_markup
		return data
	except Exception as err:
		print(err)

2.找到其他页面链接进行跳转
观察网页源代码,发现页面链接结构如下:

构造正则表达式对页面链接进行爬取,实现页面跳转

        p_link = re.compile('href="(.*?)"')
	link = str(link)
	links = re.findall(p_link, link)

3. 从每个页面爬取相应的图片
观察网页源代码

使用正则匹配,先获取所有的img标签,然后爬取img标签下面的所有图片

    imgs = soup.select('img')
    imgs = str(imgs)
    p_picture = re.compile('src="(.*?)"')		#观察html文件内容后提取出关键字
    pictures = re.findall(p_picture, imgs)		#查找图片链接

4. 调整格式输出图片链接
学号031904138,故本次共爬取138张图片

5. 图片保存到本地
共138张

1.2.2 多线程爬取

主函数逻辑同上,只是将解析页面部分改写为多线程,实现代码如下:

def imageSpider(start_url,num):		#num表示需要爬取页面的商品数量
    global threads
    global count
    try:
        req=urllib.request.Request(start_url,headers=headers)		#requests方法爬取网页
        data=urllib.request.urlopen(req)
        data=data.read()						#获取网页文本内容
        dammit=UnicodeDammit(data,["utf-8","gbk"])
        data=dammit.unicode_markup

        pic_urls = parsePage(data,num)			        # 得到图片链接pic_url的列表

        for pic_url in pic_urls:					# 多线程下载图片
            try:
                count = count + 1
                T = threading.Thread(target=download, args=(pic_url, count))
                T.setDaemon(False)
                T.start()
                threads.append(T)
            except Exception as err:
                print(err)
    except Exception as err:
            print(err)

控制台结果输出情况,依然是138张
多线程并发下载图片,下载完成顺序随机,并未按照爬取顺序下载

保存到本地结果

作业2

2.1题目

要求:使用scrapy框架复现作业1。
输出信息:同作业1

2.2实现过程

2.2.1修改settings.py

1、修改打印日志

# 修改打印日志等级 关掉一些看了也看不懂的东西
LOG_LEVEL = 'ERROR'

2、关闭遵循robots协议

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

3、设置请求头

DEFAULT_REQUEST_HEADERS = {
    "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
}

4、打开ITEM_PIPELINES

ITEM_PIPELINES = {
   'weatherPicture.pipelines.WeatherpicturePipeline': 300,
}

2.2.2编写item.py

  • 添加需要爬取的字段picture_list图片链接列表
class WeatherpictureItem(scrapy.Item):
    picture_list = scrapy.Field()

2.2.3编写pipelines.py

保存及输出picture_list

class WeatherpicturePipeline:
    def process_item(self, item, spider):
        tply = "{0:^4}\t{1:^30}"
        print(tply.format("序号", "图片链接", chr(12288)))
        for i in range(138):
            print(tply.format(i+1,item['picture_list'][i] , chr(12288)))
        path = r"D:/mymymy!/爬虫实践/scrapy/weatherPicture/pictures/"
        save2file(item['picture_list'], path)    # 保存到本地文件
        return item

2.2.4编写PictureSpider

1、观察html源代码,使用xpath解析页面

# 得到其他页面的链接
links = response.xpath('//a/@href').extract()
# 得到页面图片的链接
imgs = response.xpath('//img/@src').extract()

2、回调请求翻页

self.count += 1      # 记录第几个页面链接
if(self.num<=138):   # 记录得到的图片链接数量
    url = response.urljoin(links[self.count])
    self.count += 1
    yield scrapy.Request(url=url, callback=self.parse,dont_filter=True)
else:
    yield item

2.3输出结果

  • 控制台输出

  • 保存到本地文件

作业3

3.1题目

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

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

3.2实现过程

3.2.1 修改settings.py

同作业2此步骤

3.2.2 编写item.py

  • 添加需要爬取的字段
    这里直接将电影信息定义为二维列表

[[name1,director1,actor1,info1,score1,pic_link1],[name2...]...]

class DoubanItem(scrapy.Item):
    movies = scrapy.Field()

3.2.3 编写pipelines.py

  • 进行格式打印数据、数据库中表的创建以及插入数据到数据库、将图片下载到本地
    (调整输出格式已经重复很多次,这里就没有展示)
#-----------保存数据到数据库-----------------
def saveData2DB(datalist, dbpath):
    init_db(dbpath)
    conn = sqlite3.connect(dbpath)
    cur = conn.cursor()
    for data in datalist:
        for index in range(len(data)):
            data[index] = '"' + data[index] + '"'
            sql = '''
                insert into movie250(
                    C_name,director,actor,info,score,pic_link
                    )
                    values(%s)
            ''' % ",".join(data)
        cur.execute(sql)
        conn.commit()
    cur.close()
    conn.close()
#---------------将图片下载到本地----------------
def save2file(img_url_list,path):
    i=1
    for img in img_url_list:
        img_url = img
        new_path = path + str(i) + ".jpg"
        urllib.request.urlretrieve(img_url, new_path)		#定义存取本地图片路径
        i += 1

3.2.4 编写编写MovieSpider

  • 首先观察豆瓣top250的html源代码,看到一部电影位于一个li标签

  • 再观察每部电影内部的情况,我们需要的信息都在info标签

  • 根据源代码内容编写Xpath表达式提取相应信息,先寻找所有info标签,再从info标签内继续使用Xpath进一步提取信息

  • 要注意有些电影的简介可能为空,需要将None处理为''空字符串,否则存入数据库时会报错

# 使用xpath解析页面
            movies = response.xpath('//div[@class="info"]')
            for movie in movies:
                name = movie.xpath('div[@class="hd"]/a/span/text()').extract_first()    # 电影名称
                director_actors = movie.xpath('div[@class="bd"]/p[1]/text()[1]').extract_first().strip().replace('\xa0', '')    # 导演和主演
                # 使用正则表达式进一步分离导演和主演
                director = re.findall(p_director,str(director_actors))[0]               # 导演
                actor = re.findall(p_actor, str(director_actors))                       # 主演
                info = movie.xpath('div[@class="bd"]/p[@class="quote"]/span/text()[1]').extract_first()     # 简介
                if info != None:                       # 简介可能为空
                    info = info.replace("。", "")      # 去掉句号
                else:
                    info= " "
                score = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract_first()     # 评分
                movielist.append([name,director,actor,info,score,page[i]])
                i += 1
            item['movies'] = movielist
  • 接下来观察翻页规则,较为简单

  • 进行翻页处理,每页25部电影信息,共10页

     if self.count<=10:
         self.count += 1
         next_url = 'https://movie.douban.com/top250?start='+str(self.count*25)
         url = response.urljoin(next_url)
         yield scrapy.Request(url=url, callback=self.parse,dont_filter=True)

3.3输出结果

  • 控制台输出结果

  • 保存到数据库结果

  • 下载图片到本地结果

心得体会

  • 学习到了页面之间的跳转操作,巩固了翻页操作
  • 更加熟悉了scrapy框架与xpath信息提取方法
  • 了解单线程与多线程运行时的区别,并发执行的效率会更高
posted @ 2021-10-31 11:03  penguin02  阅读(65)  评论(0编辑  收藏  举报