Scrapy爬虫文件代码基本认识和细节解释

发布时间 2023-07-17 11:41:13作者: 蕝戀
import scrapy
from scrapy.http.request import Request
from scrapy.http.response.html import HtmlResponse
from scrapy_demo.items import ForumItem


class BaiduSpider(scrapy.Spider):
    # name必须是唯一的,因为运行一个爬虫是通过name来选择的。
    # 你需要运行命令行:scrapy crawl <name> 来执行爬虫
    name = "tieba"

    # 爬取数据的限制范围
    # 比如有时候baidu.com中就可能会加载其他域名的数据比如123.com。如果不限制scrapy会连123.com也爬。
    #
    allowed_domains = ["baidu.com"]

    # 第一次发起请求的URL,这个都是要修改的
    # 默认值是你用命令行方式创建一个爬虫时指定的<domain>
    # 命令行:scrapy genspider <name爬虫名> <domain(也就是start_urls的默认值)>
    start_urls = ["https://tieba.baidu.com"]

    def parse(self, response: HtmlResponse, **kwargs):
        """
        这个方法是自动生成的(你用scrapy genspider命令才会生成呀》。。)
        parse方法用于定义如何处理数据的
        我们主要是写这个方法.
        """
        # print(response)
        # print(type(response))
        req = response.request  # type: Request
        # print(req.url)

        # 获取响应体
        # response.body.decode("utf-8")  # 二进制数据需要decode() 这个和lxml的response.content是一样的、
        # print(response.text)

        # 使用xpath提取数据
        items = response.xpath("//ul[@id='forumList']/li[@class='rcmd_forum_item']")
        
        # 使用css选择器提取数据
        # -css取文本
        # 'a.link-title::text'
        # -css取属性
        # 'img.image-scale::attr(src)'
        # response.css()
        # response.csss("")

        result = []

        for item in items:
            forum_name = item.xpath("./a/div[@class='rcmd_forum_info']/div[@class='forum_name']/text()").get()
            forum_member = item.xpath("./a/div[@class='rcmd_forum_info']/div[@class='forum_member']/text()").get()

            # 以前我们都是自己构建字典来存储数据,现在可以用scrapy提供的Item模型类来存储数据
            # 当然了不是说你不能使用字典存,只是建议用Scrapy提供的Item模型类来存储
            # result.append({
            #     "forum_name": forum_name,
            #     "forum_member": forum_member
            # })

            # 使用框架的Item模型类来代替以前的字典
            forum_item = ForumItem()
            forum_item["forum_name"] = forum_name
            forum_item["forum_member"] = forum_member
            # 每执行yield一次,就会丢给pipeline来处理
            yield forum_item


        # print(result)

        # parse()函数中使用yield返回数据给Pipelines,
        # 注意:parse()函数中的yield能够传递的对象只能是:BaseItem, Request, dict, None
        # yield {"result": result}

    def start_requests(self):
        """
        默认爬虫第一次发起的请求是start_urls中指定的URL列表,然而默认的请求方式是GET请求
        如果你第一次请求是POST,就必须重写这个方法,然后修改请求方式
        """
        if not self.start_urls and hasattr(self, "start_url"):
            raise AttributeError(
                "Crawling could not start: 'start_urls' not found "
                "or empty (but found 'start_url' attribute instead, "
                "did you miss an 's'?)"
            )
        for url in self.start_urls:
            # 修改默认的请求方式为POST
            yield Request(url, dont_filter=True, method="GET")