" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper 博主等级

千里之行,始于足下

  • 累计撰写 206 篇文章
  • 累计创建 14 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

Scrapy基础

已删除用户
2019-10-18 / 0 评论 / 0 点赞 / 34 阅读 / 0 字
温馨提示:
本文最后更新于2024-05-28,若内容或图片失效,请留言反馈。 所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊
  • 五大组件
    • 爬虫
    • 中央引擎
    • 请求调度器
    • 下载器
    • 数据队列
  • 三大对象
    • request对象
    • response对象
    • item对象
  • 两大中间件
    • 下载中间件
    • 爬虫中间件

中央引擎从爬虫拿到第一个URL,发送给请求调度器

请求调度器处理成request对象, 返回给中央引擎

中央引擎把request对象发送给下载器(通过下载中间件)

下载器从服务器下载数据后, 处理成response对象, 返回给中央引擎

中央引擎把response对象交给爬虫, 提取数据/ 提取URL(通过爬虫中间件)

爬虫把提取到的数据(或URL),封装成item对象, 返回给中央引擎

如果是数据, 交给数据队列, 保存数据

项目初始化

  1. 创建scrapy项目: scrapy startproject 项目名
  2. 创建爬虫: cd 项目名, scrapy genspider [ -t 模板名称] 爬虫名 爬虫的域名
  3. 把第一个请求URL, 复制到start_urls中
class ItinfoSpider(scrapy.Spider):
    name = 'itinfo'
    allowed_domains = ['itcast.cn']
    start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ac']    # 这里是第一个URL(启动URL)
  1. 定义模型, 防止key写错
class ItcastItem(scrapy.Item):
    name = scrapy.Field()
    level = scrapy.Field()
    description = scrapy.Field()
  1. 编写爬虫
    • 提取完数据以后封装成数据模型对象item,并使用yield提交给引擎, 引擎会转交给管道处理
    • 对于使用xpath()提取的数据, 先提取每一行的数据, 再从每一行里面提取每一个数据
    • 对于class不同的情况, 使用css样式选择器, ".even,.odd"(逗号隔开)
    • extract()从Selector对象提取内容, extract_first()是从SelectList对象提取内容
    • 解析函数parse()本身就有xpath, 可以直接提取, 返回的是SelectorList(Selector对象列表)
    • xpath()返回的是selector对象列表, 使用extract_first()拿到第一个值
    • xpath()返回的是Selecto对象, 使用extract()获取内容
    • 直接通过标签内容提取: response.xpath('//a[text()="下一页"]')
import scrapy
from itcast.items import ItcastItem

class ItinfoSpider(scrapy.Spider):
    name = 'itinfo'
    allowed_domains = ['itcast.cn']
    start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ac'] # 这时第一个URL(启动URL)

    def parse(self, response):
        # 使用一次xpath, 获取上一级, 不直接获取名字
        div_list = response.xpath('//div[@class="li_txt"]')
        for div in div_list:
            item = ItcastItem()
            # 返回的是一个selector对象列表, 用extract_first拿到第一个
            item["name"] = div.xpath('./h3/text()').extract_first()
            item["level"] = div.xpath('./h4/text()').extract_first()
            item["description"] = div.xpath('./p/text()').extract_first()
            yield item
  1. 编写管道
    • 实现管道方法, process_item方法
    • settings.py中配置开启管道
class ItcastPipeline(object):
    def process_item(self, item, spider):
        print(dict(item))
        return item
  1. 运行爬虫: scrapy crawl 爬虫名, 不显示别的, 在settings.py中添加配置: LOG_LEVEL = "WARNING"

scrapy中每个模块具体作用

入门使用

  1. 使用管道: 编写管道代码, 注册管道
  2. 使用回调函数处理不同的页面: call_back=, 如果不指定, 默认为parse
  3. 存储不同数据时, 新建模型类, 管道里面使用if isinstance(item,TencentItem)判断不同的模型类
  4. 存储相同数据时, 把item放到meta(字典, 用来传递数据)中, 通过response.meta获取
import json
import scrapy
from tencent.items import TencentItem, DetailItem

class ZhaopinSpider(scrapy.Spider):
    name = 'tencent_5'
    allowed_domains = ['tencent.com']
    base_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?pageIndex={}'

    def start_requests(self):
        # 引擎会自动回调这个方法, 提供给引擎首次请求的URL列表
        for page in range(1, 489):
            yield scrapy.Request(
                url=self.base_url.format(page),
            )
    
    def parse(self, response):
        """
        获取响应, 触发解析函数, 提取数据, 提取URL
        :param response: 下载==>中央引擎==>爬虫 的response对象
        :return: 数据 URL
        """
        response_dict = json.loads(response.text)
        response_data = response_dict["Data"]
        info_count = response_data["Count"] # 所有显示的条数
        for info in response_data["Posts"]:
            item = TencentItem()
            item["Name"] = info["RecruitPostName"]
            item["Location"] = info["CountryName"] + info["LocationName"]
            item["BG"] = info["BGName"]
            item["Category"] = info["CategoryName"]
            item["Time"] = info["LastUpdateTime"]
    
            detail_info = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?postId='
            post_id = info["PostId"]
            yield scrapy.Request(
                url=detail_info + post_id,
                callback=self.parse_detail, # 设置回调解析函数
                meta={"item": item} # 用meta携带item, response.meta, 字典类型
            )
            break # 测试
    
    def parse_detail(self, response):
        # 详情页解析函数
        response_dict = json.loads(response.text)
        item = response.meta["item"]
        item["Responsibility"] = response_dict["Data"]["Responsibility"]
        item["Requirement"] = response_dict["Data"]["Requirement"]
        yield item

配置信息

# 项目名
BOT_NAME = 'tencent'

# 爬虫位置
SPIDER_MODULES = ['tencent.spiders']
NEWSPIDER_MODULE = 'tencent.spiders'

# 日志级别
LOG_LEVEL = "WARNING"

# 设置默认的用户身份 ==> 自己配置改成浏览器的
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'

# 是否遵循robots协议, 不让你怕, 是不是就不爬了 ==> 默认True
ROBOTSTXT_OBEY = False

# 最大连接数, 默认16, 并发请求数, 默认注释32
CONCURRENT_REQUESTS = 5

# 下载延迟
DOWNLOAD_DELAY = 3

# 对每个域名, 同时并发请求数
CONCURRENT_REQUESTS_PER_DOMAIN = 16

# 对每个IP, 同时并发请求数
CONCURRENT_REQUESTS_PER_IP = 16

# 是否关闭cookie, 默认开启==>False
COOKIES_ENABLED = False

# 是否开启远程控制
TELNETCONSOLE_ENABLED = False

# 默认请求头
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
}

# 设置爬虫中间件
SPIDER_MIDDLEWARES = {
'tencent.middlewares.TencentSpiderMiddleware': 543,
}

# 设置下载中间件
DOWNLOADER_MIDDLEWARES = {
'tencent.middlewares.TencentDownloaderMiddleware': 543,
}

# 设置扩展
EXTENSIONS = {
scrapy.extensions.telnet.TelnetConsole': None,
}

# 设置管道
ITEM_PIPELINES = {
    'tencent.pipelines.TencentPipeline': 300,
    'tencent.pipelines.MongodbListItemPipeline': 301,
    'tencent.pipelines.MongodbDetailItemPipeline': 302,
}

# 设置用户名和密码
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
AUTOTHROTTLE_DEBUG = False

# 是否缓存请求
HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 0
HTTPCACHE_DIR = 'httpcache' # 本地 ==> 当前文件夹下.scrapy文件夹中的httpcache中, 下次对于相同域名, 先从缓存中提取请求
HTTPCACHE_IGNORE_HTTP_CODES = [403, 404, 500, ] # 哪些 请求状态 数不需要缓存的
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

CrawlSpider

自带去重功能:

把提取的URL添加到set中, 如果提取的数据已经在set中了, 就不添加了

原因: URL的查询字符串位置不同, 对set()来说就是不同的数据

解决: 把参数也写到规则中

基本使用

  1. 必须继承自CrawlSpider
  2. 要设置ruls属性
  3. 编写解析函数

爬取流程

  1. 通过规则提取链接
  2. 跟进链接获取内容
  3. 通过规则从内容中获取链接
  4. 跟进链接获取内容

提取规则

ruls: 表示内容提取的规则, 包含规则列表(元组)

  • Rule: 表示规则对象
    • LinkrExtractor: 链接提取器, 提取链接的规则参数
      • allow=(): 提取数据的条件(使用正则表达式)
      • deny=(): 过滤数据的条件(使用正则表达式), deny优先于allow
      • allow_domains=(): 允许的域名, 网站的静态文件和网页不在同一域名下
      • deny_domains=(): 过滤的域名, deny_domains 优先于 allow_domains
      • restrict_xpaths=(): 通过xpath提取链接
      • tags=('a', 'area'): 设置提取内容链接的标签, 默认是a, area
      • attrs=('href',): 设置提取内容标签的属性, 默认是href
      • restrict_css=(): 通过CSS样式选择器提取内容
      • strip=True: 提取内容后去掉两边的空格
    • callback: 当请求成功后的回调函数
    • follow :是否跟进,提取链接的内容这个循环是否继续

  • 使用//td[@class='12th']..获取上一级元素, ..表示上一级
  • 获取第三个a标签的下一个a标签:"//a[@id='3']/following-sibling::a[1]"
  • 获取第三个a标签后面的第N个标签:"//a[@id='3']/following-sibling::*[N]"
  • 获取第三个a标签的上一个a标签:"//a[@id='3']/preceding-sibling::a[1]"
  • 获取第三个a标签的前面的第N个标签:"//a[@id='3']/preceding-sibling::*[N]"
  • 获取第三个a标签的父标签:"//a[@id=='3']/.."
  • 如果在for循环下面就用extract(), 如果直接取值就用extract_first()(列表取值)

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区