2023数据采集与融合技术实践作业三

发布时间 2023-10-21 10:10:29作者: 酱酱酱酱江

码云链接

作业①:

要求:指定一个网站,爬取这个网站中的所有的所有图片,例如:中国气象网(http://www.weather.com.cn)。使用scrapy框架分别实现单线程和多线程的方式爬取。
–务必控制总页数(学号尾数2位)、总下载的图片数量(尾数后3位)等限制爬取的措施。

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

实验

爬取中国气象网:

天气网代码
image.py

import scrapy
from weather.items import WeatherItem

class ImageSpider(scrapy.Spider):
    name = "image"
    allowed_domains = ["www.weather.com.cn"]
    start_urls = ["http://www.weather.com.cn/"]

    def parse(self, response):
        img_list = response.xpath('//img/@src').extract()
        for img in img_list:
            imgs = WeatherItem(img=img)
            yield imgs

这里可以知道很多网站的图片都在xpath('//img/@src')下面,但是也有例外

pipelines.py

class jsonPipeline:

    # 以下模式不推荐 因为每传递一个对象 那么就打卡一次文件 对文件的操作过于频繁
    #
    # item就是yield后面的book对象
    def process_item(self, item, spider):
        #  (1)write方法必须是字符串,不能是对象
        # (2)w模式 会每一个对象都打开一次文件 覆盖之前的内容
        # with open('book.json','a',encoding='utf-8')as fp:
        #       fp.write(str(item))
        print(item.get('img'))
        return item

    def close_spider(self, spider):
        self.fp.close()
class WeatherPipeline:
    def open_spider(self, spider):
        self.folder_path = 'C:\Programming\python\pythonProject\大数据采集\大数据采集实践\实践3\weather\image\\'  # 设置保存图片的文件夹路径

    def process_item(self, item, spider):
        image_url = item['img']  # 假设图片地址存储在 item 的 'image_url' 字段中

        # 使用 urllib 下载图片
        file_name = image_url.split('/')[-1]  # 图片文件名
        file_path = self.folder_path + file_name  # 图片保存的完整路径
        urllib.request.urlretrieve(image_url, file_path)

        return item

    def close_spider(self, spider):
        pass

采用多管道运行,下载图片速度更快

结果如下:

心得体会:

因为气象网没有页数可以翻页所以又爬取了其他网页 与上面代码有几点不同的地方:
1.使用xpath('//img/@src')爬取网页发现很多图片无法加载,这是因为网页采用了懒加载,只有等滑倒下面之后,图片的地址才从xpath('.//img/@data-original')加载到@src
2.因为每一页逻辑是一样的 只需要每页的请求再次调用parse方法就可以了,如果每页的逻辑不同就另写一个方法(如爬取当当网),
第一个方法返回第二页的地址,因为第一页没有图片地址,要点击进去才能看到图片获取地址(如爬取电影网)

爬取当当网:
当当代码

import scrapy
from scrapy_dangdang.items import ScrapyDangdangItem



class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["http://category.dangdang.com/cp01.01.02.00.00.00.html"]
    base_url='http://category.dangdang.com/pg'
    page=1
    def parse(self, response):
        # 图片//ul[@id="component_59"]/li//img/@src
        # src=scrapy.Field()
        # 名字//ul[@id="component_59"]/li//img/@alt
        # name=scrapy.Field()
        # 价格//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()
        # price=scrapy.Field()
        li_list = response.xpath('//ul[@id ="component_59"]/li')
        for li in li_list:
            # 懒加载
            src = li.xpath('.//img/@data-original').extract_first()
            if src:
                src = src
            else:
                src = li.xpath('.//img/@src').extract_first()


            book = ScrapyDangdangItem(src=src)
            # 获取一个book就将book交给pipelines
            yield book
# 每一页逻辑是一样的 只需要每页的请求再次调用parse方法就可以了
        if self.page < 100:
            self.page=self.page+1
            url=self.base_url+str(self.page)+'-cp01.01.02.00.00.00.html'
            # 怎么调用parse方法
            yield scrapy.Request(url=url,callback=self.parse)
结果如下:


爬取电影网:
电影网代码

import scrapy
from scrapy_movie.items import ScrapyMovieItem


class MvSpider(scrapy.Spider):
    name = "mv"
    allowed_domains = ["www.dytt.to"]
    start_urls = ["https://www.dytt.to/html/gndy/china/index.html"]

    def parse(self, response):
        # 要第一页的名字 和第二页的图片
        a_list = response.xpath('//div[@class="co_content8"]//td[2]//a[2]')
        for a in a_list:
            # 获取第一页的name 和第二页要点击的链接
            name = a.xpath('./text()').extract_first()
            href = a.xpath('./@href').extract_first()

            # 第二页的地址
            url = 'https://www.dytt.to' + href
            print(url)

            # 对第二页发起访问
            yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})

    def parse_second(self, response):
        src = response.xpath('//div[@id="Zoom"]//img[1]/@src').extract_first()
        name = response.meta['name']
        movie=ScrapyMovieItem(src=src,name=name)
        yield movie
结果如下:


作业②

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取股票相关信息。
候选网站:东方财富网:https://www.eastmoney.com/

输出信息:MySQL数据库存储和输出格式如下:
表头英文命名例如:序号id,股票代码:bStockNo……,由同学们自行定义设计
序号 股票代码 股票名称 最新报价 涨跌幅 涨跌额 成交量 振幅 最高 最低 今开 昨收
1 688093 N世华 28.47 10.92 26.13万 7.6亿 22.34 32.0 28.08 30.20 17.55
2……
Gitee文件夹链接

实验

股票代码

from typing import Iterable
import scrapy
from scrapy.http import Request
import json
# from ..items import Homework01Item
import pandas as pd
from sqlalchemy.engine import create_engine


class StockSpider(scrapy.Spider):
    name = "scrapy_stock"
    allowed_domains = ["eastmoney.com"]
    start_urls = ["http://38.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112406848566904145428_1697696179672&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1697696179673"]

    def start_requests(self):
        for url in self.start_urls:
            yield Request(url)

    def parse(self, response):
        content = response.text[response.text.find('(') + 1:response.text.rfind(')')]
        obj = json.loads(content)
        data = obj['data']['diff']
        goods_list = []
        name = ['f12', 'f14', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f15', 'f16', 'f17', 'f18']
        count = 0
        for li in data:
            list = [count]
            for n in name:
                list.append(li[n])
            count += 1
            goods_list.append(list)
        df = pd.DataFrame(data=goods_list,
                          columns=['序号', '股票代码', '股票名称', '最新报价', '涨跌幅', '涨跌额', '成交量', '成交额',
                                   '振幅', '最高', '最低', '今开', '昨收'])
        df.set_index('序号')
        print(df)
        engine = create_engine("mysql+mysqlconnector://root:021022@127.0.0.1:3306/mybatis")
        df.to_sql("stock", engine, if_exists="replace", index=False)
结果如下:

心得体会:

之前写的数据库都是sqlit的数据库,这次又学会了如何创建和插入mysql数据库,收获满满~

作业③:

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。
候选网站:中国银行网:https://www.boc.cn/sourcedb/whpj/
输出信息:
Gitee文件夹链接
Currency TBP CBP TSP CSP Time
阿联酋迪拉姆 198.58 192.31 199.98 206.59 11:27:14

实验

银行代码

import scrapy
import pandas as pd
from sqlalchemy.engine import create_engine


class BankSpider(scrapy.Spider):
    name = "bank"
    allowed_domains = ["www.boc.cn"]
    start_urls = ["https://www.boc.cn/sourcedb/whpj/"]

    def parse(self, response):
        rows = response.xpath("//tr[position()>1]")

        data = []
        # 遍历每个<tr>元素
        for row in rows:
            lis=[]
            Currency = row.xpath(".//td[1]/text()").extract_first()
            TBP=row.xpath(".//td[2]/text()").extract_first()
            CBP=row.xpath(".//td[3]/text()").extract_first()
            TSP=row.xpath(".//td[4]/text()").extract_first()
            CSP=row.xpath(".//td[5]/text()").extract_first()
            Time=row.xpath(".//td[8]/text()").extract_first()
            lis.append(Currency)
            lis.append(TBP)
            lis.append(CBP)
            lis.append(TSP)
            lis.append(CSP)
            lis.append(Time)
            data.append(lis)
        df = pd.DataFrame(data=data,columns=['Currency', 'TBP', 'CBP', 'TSP', 'CSP', 'Time'])
        print(df)
        engine = create_engine("mysql+mysqlconnector://root:021022@127.0.0.1:3306/mybatis")
        df.to_sql("bank", engine, if_exists="replace", index=False)

        pass
结果如下:

心得体会:

xpath("//tr[position()>1]")表示从列表第二个开始