Python安装使用Scrapy框架


Posted in Python onApril 12, 2022

一、架构介绍

Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。

Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。整体架构大致如下

IO多路复用

Python安装使用Scrapy框架

# 引擎(EGINE)(大总管)

引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分。

# 调度器(SCHEDULER)

用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

# 下载器(DOWLOADER)

用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的

# 爬虫(SPIDERS)

SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求

# 项目管道(ITEM PIPLINES)

在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作

# 两个中间件

-爬虫中间件

-下载中间件(用的最多,加头,加代理,加cookie,集成selenium)

二、安装创建和启动

# 1 框架 不是 模块
# 2 号称爬虫界的django(你会发现,跟django很多地方一样)
# 3 安装
	-mac,linux平台:pip3 install scrapy
  -windows平台:pip3 install scrapy(大部分人可以)
  	- 如果失败:
      1、pip3 install wheel #安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
      3、pip3 install lxml
      4、pip3 install pyopenssl
      5、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
      6、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
      7、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
      8、pip3 install scrapy
 # 4 在script文件夹下会有scrapy.exe可执行文件
	-创建scrapy项目:scrapy startproject 项目名   (django创建项目)
  	-创建爬虫:scrapy genspider 爬虫名 要爬取的网站地址   # 可以创建多个爬虫
 # 5 命令启动爬虫
		-scrapy crawl 爬虫名字
  		-scrapy crawl 爬虫名字 --nolog   # 没有日志输出启动
 # 6 文件执行爬虫(推荐使用)
	-在项目路径下创建一个main.py,右键执行即可
  	from scrapy.cmdline import execute
    # execute(['scrapy','crawl','chouti','--nolog'])  # 没有设置日志级别
    execute(['scrapy','crawl','chouti'])			  # 设置了日志级别

三、配置文件目录介绍

-crawl_chouti   # 项目名
  -crawl_chouti # 跟项目一个名,文件夹
    -spiders    # spiders:放着爬虫  genspider生成的爬虫,都放在这下面
    	-__init__.py
      -chouti.py # 抽屉爬虫
      -cnblogs.py # cnblogs 爬虫
    -items.py     # 对比django中的models.py文件 ,写一个个的模型类
    -middlewares.py  # 中间件(爬虫中间件,下载中间件),中间件写在这
    -pipelines.py   # 写持久化的地方(持久化到文件,mysql,redis,mongodb)
    -settings.py    # 配置文件
  -scrapy.cfg       # 不用关注,上线相关的
# 配置文件settings.py
ROBOTSTXT_OBEY = False   # 是否遵循爬虫协议,强行运行
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'    # 请求头中的ua,去浏览器复制,或者用ua池拿
LOG_LEVEL='ERROR' # 这样配置,程序错误信息才会打印,
	#启动爬虫直接 scrapy crawl 爬虫名   就没有日志输出
  	# scrapy crawl 爬虫名 --nolog  # 配置了就不需要这样启动了
# 爬虫文件
class ChoutiSpider(scrapy.Spider):
    name = 'chouti'   # 爬虫名字
    allowed_domains = ['https://dig.chouti.com/']  # 允许爬取的域,想要多爬就注释掉
    start_urls = ['https://dig.chouti.com/']   # 起始爬取的位置,爬虫一启动,会先向它发请求
    def parse(self, response):  # 解析,请求回来,自动执行parser,在这个方法中做解析
        print('---------------------------',response)

Python安装使用Scrapy框架

四、爬取数据,并解析

# 1 解析,可以使用bs4解析
from bs4 import BeautifulSoup
soup=BeautifulSoup(response.text,'lxml')
soup.find_all()  # bs4解析
soup.select()  # css解析
# 2 内置的解析器
response.css  
response.xpath
# 内置解析 
  # 所有用css或者xpath选择出来的都放在列表中
  # 取第一个:extract_first()
  # 取出所有extract()
# css选择器取文本和属性:
    # .link-title::text  # 取文本,数据都在data中
    # .link-title::attr(href)   # 取属性,数据都在data中
# xpath选择器取文本和属性
    # .//a[contains(@class,"link-title")/text()]
    #.//a[contains(@class,"link-title")/@href]
# 内置css选择期,取所有
div_list = response.css('.link-con .link-item')
for div in div_list:
    content = div.css('.link-title').extract()
    print(content)

五、数据持久化

# 方式一(不推荐)
  -1 parser解析函数,return 列表,列表套字典
    # 命令   (支持:('json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')
    # 数据到aa.json文件中
  -2 scrapy crawl chouti -o aa.json   
# 代码:
lis = []
for div in div_list:
    content = div.select('.link-title')[0].text
    lis.append({'title':content})
    return lis
# 方式二 pipline的方式(管道)
   -1 在items.py中创建模型类
   -2 在爬虫中chouti.py,引入,把解析的数据放到item对象中(要用中括号)
   -3 yield item对象
   -4 配置文件配置管道
       ITEM_PIPELINES = {
        # 数字表示优先级(数字越小,优先级越大)
       'crawl_chouti.pipelines.CrawlChoutiPipeline': 300,
       'crawl_chouti.pipelines.CrawlChoutiRedisPipeline': 301,
    	}
  -5 pipline.py中写持久化的类
        spider_open  # 方法,一开始就打开文件
        process_item # 方法,写入文件
        spider_close # 方法,关闭文件

保存到文件

# choutiaa.py 爬虫文件
import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            yield item  # 必须用yield  	
# items.py 模型类文件
import scrapy
class ChoutiItem(scrapy.Item):
    content = scrapy.Field()
    href = scrapy.Field()
# pipelines.py 数据持久化文件
class ChoutiPipeline(object):
    def open_spider(self, spider):
        # 一开始就打开文件
        self.f = open('a.txt', 'w', encoding='utf-8')
    def process_item(self, item, spider):
        # print(item)
        # 写入文件的操作
        self.f.write(item['content'])
        self.f.write(item['href'])
        self.f.write('\n')
        return item
    def close_spider(self, spider):
        # 写入完毕,最后关闭文件
        self.f.close()
# setting.py
ITEM_PIPELINES = {
    # 数字表示优先级,越小优先级越高
   'chouti.pipelines.ChoutiPipeline': 300,
   'chouti.pipelines.ChoutiRedisPipeline': 301,
}

保存到redis

# settings.ps
ITEM_PIPELINES = {
    # 数字表示优先级,越小优先级越高
   'chouti.pipelines.ChoutiPipeline': 300,
   'chouti.pipelines.ChoutiRedisPipeline': 301,
}
# pipelines.py
# 保存到redis
from redis import Redis
class ChoutiRedisPipeline(object):
    def open_spider(self, spider):
        # 不写参数就用默认配置
        self.conn = Redis(password='123')  # 一开始就拿到redis对象
    def process_item(self, item, spider):
        print(item)
        import json
        s = json.dumps({'content': item['content'], 'href': item['href']})
        self.conn.hset('choudi_article', item['id'], s)
        return item
    def close_spider(self, spoder):
        pass
        # self.conn.close()
# chouti.py
import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            id = div.attrs['data-id']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            item['id'] = id
            yield item  # 必须用yield

保存到MongoDB

#一.下载并安装mongodb
pip install pymongo
#二、在settings中打开PIPELINES并把数据库相应配置写入
ITEM_PIPELINES = {
    '<spider_name>.pipelines.ChoutiPipeline': 300,
}
MONGODB_HOST = '127.0.0.1'
# 端口号,默认27017
MONGODB_PORT = 27017
# 设置数据库名称
MONGODB_DBNAME = 'Chouti'
# 存放本数据的表名称
MONGODB_DOCNAME = 'Chouti'
#三.修改pipelines文件
import pymongo
from scrapy.utils.project import get_project_settings
settings = get_project_settings()
class DouluodaluPipeline(object):
    def __init__(self):
        # 获取setting主机名、端口号和数据库名称
        host = settings['MONGODB_HOST']
        port = settings['MONGODB_PORT']
        dbname = settings['MONGODB_DBNAME']
        # 创建数据库连接
        client = pymongo.MongoClient(host=host,port=port)
        # 指向指定数据库
        mdb = client[dbname]
        # 获取数据库里面存放数据的表名
        self.post = mdb[settings['MONGODB_DOCNAME']]
    def process_item(self, item, spider):
        data = dict(item)
        # 向指定的表里添加数据
        self.post.insert(data)
        return item

保存到mysql

import pymysql.cursors
class MySQLPipeline(object):
    def __init__(self):
        # 连接数据库
        self.connect = pymysql.connect(
            host='127.0.0.1',  # 数据库地址
            port=3306,  # 数据库端口
            db='scrapyMysql',  # 数据库名
            user='root',  # 数据库用户名
            passwd='root',  # 数据库密码
            charset='utf8',  # 编码方式
            use_unicode=True)
        # 通过cursor执行增删查改
        self.cursor = self.connect.cursor()
    def process_item(self, item, spider):
        self.cursor.execute(
            """insert into mingyan(tag, cont)
            value (%s, %s)""",  # 纯属python操作mysql知识,不熟悉请恶补
            (item['tag'],  # item里面定义的字段和表字段对应
             item['cont'],))
        # 提交sql语句
        self.connect.commit()
        return item  # 必须实现返回

六、动作链,控制滑动的验证码

from selenium import webdriver
from selenium.webdriver import ActionChains
import time
bro=webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
bro.implicitly_wait(10)
#切换frame(很少)
bro.switch_to.frame('iframeResult')
div=bro.find_element_by_xpath('//*[@id="draggable"]')
# 1 生成一个动作练对象
action=ActionChains(bro)
# 2 点击并夯住某个控件
action.click_and_hold(div)
# 3 移动(三种方式)
# action.move_by_offset() # 通过坐标(x,y)
# action.move_to_element() # 到另一个标签
# action.move_to_element_with_offset() # 到另一个标签,再偏移一部分
for i in range(5):
    action.move_by_offset(10,10)
# 4 真正的移动
action.perform()

# 5 释放控件(松开鼠标)
action.release()

async def login():
    for res in setting.user:
        try:
            username = res[0]
            password = res[1]
            # headless参数设为False,则变成有头模式
            browser = await launch(
                {'headless': False}
            )
            # 打开一个页面
            page = await browser.newPage()
            await page.setViewport(viewport={'width': 1280, 'height': 800})
            res = await page.goto('https://login.taobao.com/', options={'timeout': 10000})
            await page.type('#fm-login-id', username)
            await page.type('#fm-login-password', password)
            await page.waitFor(1000)  # 等待时间
            slider = await page.querySelector('#nc_1_n1z')  # 是否有滑块
            if slider:
                try:
                    print('有滑块')
                    await page.hover('#nc_1_n1z')  # 不同场景的验证码模块能名字不同。
                    await page.mouse.down()
                    await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})
                    await page.mouse.up()
                except Exception as e:
                    print(e)
                    input('验证失败,人工登录:')
            else:
                print('没有滑块')
            await page.click("#login-form > div.fm-btn > button")  # 点击登录
            input('进入登录成功页面后,按回车:')
            return page
        except Exception as e:
            continue

七、提高爬取效率

- 在配置文件中进行相关的配置即可:(默认还有一套setting)
#1 增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
#2 提高日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO'
# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
# 4禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s

八、fake-useragent池

# pip3 install fake-useragent
from fake_useragent import UserAgent
ua = UserAgent(verify_ssl=False)
print(ua.random)  # 随机获取一个UserAgent

九、中间件配置

#大中间件:下载中间件,爬虫中间件
# 1 写在middlewares.py中(名字随便命名)
# 2 配置生效()
# 爬虫中间件
SPIDER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlSpiderMiddleware': 543,
}
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlDownloaderMiddleware': 543,
}
# 下载中间件
# 在cnblogs_crawl.middlewares.CnblogsCrawlDownloaderMiddleware中有五个方法
# 请求出去的时候
def process_request(self, request, spider)
	# Must either:
    # - return None:   # 返回none继续处理,进入下一个中间件
    # - return Response: 当次请求结束,把Response丢给引擎处理(可以自己爬,包装成Response)
    # - return Request : 相当于把Request重新给了引擎,引擎再去做调度
    # - 抛异常:执行process_exception
# 请求回来的时候
def process_response(self, request, response, spider)
	# - return a Response object :继续处理当次Response,继续走后续的中间件
    # - return a Request object:重新给引擎做调度
	# - 抛异常:执行process_exception
# 请求异常的时候
def process_exception(self, request, exception, spider)
	# - return None: 不处理异常,继续丢给下面
    # - return a Response:停止异常处理,不丢给下面。给引擎。Response给爬虫分析数据
    # - return a Request:停止异常处理,不丢给下面。给引擎。Request重新调度

process_exception 错误处理

class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs4'
    allowed_domains = ['www.cnblogs.com']
    start_urls = ['http://wwwsadasd.cnblogs.com/']   # 错误的网址,报错走异常处理
# 走异常处理,重新返回一个正确的Request对象
def process_exception(self, request, exception, spider):
    print(request.url)  # http://wwwsadasd.cnblogs.com/
    from scrapy.http import Request
    return Request('http://www.cnblogs.com/',callback=spider.parser_detail)

process_request 加代理,加cookie等

def process_request(self, request, spider):
        # 1 加cookie(request.cookies就是访问该网站的cookie)
        print(request.cookies)
        request.cookies={'name':"jeff",'age':18}  # 从你的cookie池中取出来的,  字典
        print(request.cookies)
        # 2 加代理
        request.meta['proxy']=self.get_proxy()   # 从代理池中获取一个
        print(request.meta['proxy'])
        # 3 修改ua
        from fake_useragent import UserAgent   # ua模块,随机获取一个
        ua = UserAgent(verify_ssl=False)
        request.headers['User-Agent']=ua.random
        print(request.headers)
# 代理池
def get_proxy(self):
    import requests
    ret=requests.get('http://0.0.0.0:5010/get').json()['proxy']
    print(ret)
    return ret
        return None

十、集成selenium

#可在两个地方集成。
#1.process_request(请求出去的时候)  # 推荐写这里,少请求一次。直接集成封装
#2.process_response(请求回来的时候) # 不推荐,因为夺走了一次请求,回来再集成封装
# 方案一:缺点很大。每次一请求都要打开一个bro浏览器
def process_request(self, request, spider):
    from selenium import webdriver
    from scrapy.http import HtmlResponse
    bro = webdriver.Chrome(executable_path='../chromedriver')
    bro.get(request.url)
    text = bro.page_source
    response = HtmlResponse(url=request.url, body=text.encode('utf-8'), status=200)
    return response
# 方案二:改进为一开始就打开一个bro浏览器,后面都用这一个bro
class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    from selenium import webdriver
    # 在爬虫一开始就打开bro对象
    bro = webdriver.Chrome(executable_path='../chromedriver')  
    # 在爬虫中新添加的方法:关闭bro
    def close(spider, reason):
    	spider.bro.close()  # 爬虫结束关闭
# 中间件中
def process_request(self, request, spider):
    from scrapy.http import HtmlResponse
    spider.bro.get(request.url)  # 每个请求使用一个bro
    text = spider.bro.page_source
    response = HtmlResponse(url=request.url, body=text.encode('utf-8'), status=200)
    return response

十一、指纹和布隆过滤器实现增量爬取

什么是增量爬取?

-增量爬取(100链接,150个链接)

  • -已经爬过的,放到某个位置(mysql,redis中:集合)
  • -如果用默认的,爬过的地址,放在内存中,只要项目一重启,就没了,它也不知道我爬过那个了,所以要自己重写去重方案

-你写的去重方案,占得内存空间更小

    -bitmap方案

    -BloomFilter布隆过滤器

网址指纹

# 一、网址指纹
from scrapy.http import Request
from scrapy.utils.request import request_fingerprint
# 这种网址是一个
request1 = Request(url='https://www.baidu.com/s?name=jeff&age=18')
request2 = Request(url='https://www.baidu.com/s?age=18&name=jeff')
ret1=request_fingerprint(requests1)
ret2=request_fingerprint(requests2)
print(ret1) # 6961985868392ae44c15ada494ddeda856cf75fc
print(ret2) # 6961985868392ae44c15ada494ddeda856cf75fc

布隆过滤器

# 安装
# 1.需要先安装bitarray  #下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/
# 2.下载好之后 pip3 install 文件拖进去
# 3.pip3 install pybloom_live
#ScalableBloomFilter 可以自动扩容
from pybloom_live import ScalableBloomFilter
bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH)
url = "https://www.baidu.com/s?name=jeff&age=18"
url2 = "https://www.baidu.com/s?age=18&name=jeff"
bloom.add(url)
print(url in bloom)
print(url2 in bloom)

使用一:添加网址(不推荐)

#BloomFilter 是定长的
from pybloom_live import BloomFilter
bf = BloomFilter(capacity=1000)
url='www.baidu.com'
bf.add(url)
print(url in bf)
print("www.liuqingzheng.top" in bf)

使用二:添加网址指纹(推荐),配合指纹使用

from scrapy.http import Request
from scrapy.utils.request import request_fingerprint
from pybloom_live import BloomFilter
request1 = Request(url='https://www.baidu.com/s?name=jeff&age=18')
request2 = Request(url='https://www.baidu.com/s?age=18&name=jeff')
ret1=request_fingerprint(request1)
ret2=request_fingerprint(request2)
print(ret1) # 6961985868392ae44c15ada494ddeda856cf75fc
print(ret2) # 6961985868392ae44c15ada494ddeda856cf75fc
bf = BloomFilter(capacity=1000) # 1000容量
bf.add(ret2)
if ret1 in bf:
    print('已经爬过此网站,True')
else:
    bf.add(ret1)  # 添加
    print('还没有爬过此网站,返回false')

十二、分布式爬虫

github地址:https://github.com/rmax/scrapy-redis
# 1 安装pip3 install scrapy-redis
# 源码部分,不到1000行,
# 1 原来的爬虫继承
from scrapy_redis.spiders import RedisSpider
class CnblogsSpider(RedisSpider):
  	#start_urls = ['http://www.cnblogs.com/']
    redis_key = 'myspider:start_urls'  # 起始地址为空,在redis中拿
# 2 在setting中配置
  SCHEDULER = "scrapy_redis.scheduler.Scheduler"
  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
  ITEM_PIPELINES = { 
     'chouti.pipelines.Pipeline': 300,               # 用自己的入库类,比如mysql中
     # 'scrapy_redis.pipelines.RedisPipeline': 300  # 存在别人写好的redis入库类
  }
REDIS_PARAMS  = {'password':'123'}   # 如果redis有密码就配置
#其他更多配置见github
# 3 多台机器上启动scrapy
# 4 向reids中发送起始url
redis-cli lpush myspider:start_urls https://www.cnblogs.com

十三、爬虫框架全站爬取使用案例

可以同时启动两个爬虫,爬不同的网站。但是建议爬不同的网站新建项目

chouti.py 爬虫:

import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            id = div.attrs['data-id']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            item['id'] = id
            yield item  # 必须用yield

cnblogs.py 爬虫:

# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from chouti.items import CnblogsItem  # 导入模型类
from scrapy.http import Request
class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    start_urls = ['https://www.cnblogs.com/']
    def parse(self, response):
        print('------', response)
        soup = BeautifulSoup(response.text, 'lxml')
        div_list = soup.select('#post_list .post_item')
        for div in div_list:
            author = div.select('.post_item_foot a')[0].text
            content_url = div.select('h3 a')[0].attrs['href']
            title = div.select('h3')[0].text
            content_summary = div.select('p')[0].text
            item = CnblogsItem()
            item['author'] = author
            item['content_url'] = content_url
            item['title'] = title
            item['content_summary'] = content_summary
            # print(f'''
            # 作者:{author}
            # 文章地址:{content_url}
            # 标题:{title}
            # 文章内容:{content_summary}
            # ''')            
            # 继续往深一层爬取,传递给content_parse
            yield Request(content_url, callback=self.content_parse, meta={'item': item})
        # 获取下一页的标签网址
        next = soup.select('#paging_block > div > a:nth-last-child(1)')[0].attrs['href']
        next = 'https://www.cnblogs.com/'+next
        yield Request(next)   # 继续爬取下一页
    def content_parse(self, response):
        item = response.meta.get('item')
        content = response.css('#cnblogs_post_body').extract_first()
        if not content:
            content = response.css('content').extract_first()
        item['content'] = content
        # print(item)
        yield item

items.py 模型类:

# -*- coding: utf-8 -*-
# Define here the models for your scraped items
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ChoutiItem(scrapy.Item):
    content = scrapy.Field()
    href = scrapy.Field()
    id = scrapy.Field()
class CnblogsItem(scrapy.Item):
    author = scrapy.Field()
    content_url = scrapy.Field()
    title = scrapy.Field()
    content_summary = scrapy.Field()
    content = scrapy.Field()

pipelines.py 数据持久化文件

# -*- coding: utf-8 -*-
# Define your item pipelines here
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# 保存到文件
class Pipeline(object):
    def open_spider(self, spider):
        # choutiaa爬虫入库前
        if spider.name == 'choutiaa':
            # 一开始就打开文件
            self.f = open('a.txt', 'w', encoding='utf-8')
        # cnblog爬虫入库前
        elif spider.name == 'cnblogs':
            import pymysql
            self.conn = pymysql.Connect(host='127.0.0.1', port=3306, db='cnblogs', user='root', password="123",autocommit=True)
    def process_item(self, item, spider):
        # choutiaa爬虫入库中
        if spider.name == 'choutiaa':
            # 写入文件的操作
            self.f.write(item['content'])
            self.f.write(item['href'])
            self.f.write(item['id'])
            self.f.write('\n')
            return item
        # cnblog爬虫入库中
        elif spider.name == 'cnblogs':
            print('cnblogs入库中')
            curser = self.conn.cursor()
            sql = 'insert into article (author,content_url,title,content_summary,content) values (%s,%s,%s,%s,%s)'
            curser.execute(sql, (
            item['author'], item['content_url'], item['title'], item['content_summary'], item['content']))
    def close_spider(self, spider):
        # choutiaa爬虫入库结束
        if spider.name == 'choutiaa':
            # 写入完毕,最后关闭文件
            self.f.close()
        # cnblog爬虫入库结束
        elif spider.name == 'cnblogs':
            print('cnblogs入库完毕')
            self.conn.close()

main.py

from scrapy.cmdline import execute
# execute(['scrapy','crawl','choutiaa'])
execute(['scrapy','crawl','cnblogs'])

以上就是scarpy爬虫框架集成selenium及详细讲解的详细内容!

Python 相关文章推荐
全面解析Python的While循环语句的使用方法
Oct 13 Python
Python制作爬虫采集小说
Oct 25 Python
Python数据操作方法封装类实例
Jun 23 Python
Python批量合并有合并单元格的Excel文件详解
Apr 05 Python
python抓取搜狗微信公众号文章
Apr 01 Python
PYQT5设置textEdit自动滚屏的方法
Jun 14 Python
Python3 翻转二叉树的实现
Sep 30 Python
Python操作SQLite/MySQL/LMDB数据库的方法
Nov 07 Python
python中resample函数实现重采样和降采样代码
Feb 25 Python
python实现门限回归方式
Feb 29 Python
Python命名空间namespace及作用域原理解析
Jun 05 Python
Python中全局变量和局部变量的理解与区别
Feb 07 Python
Python使用华为API为图像设置多个锚点标签
python实现手机推送 代码也就10行左右
Apr 12 #Python
Python内置包对JSON文件数据进行编码和解码
详细介绍python操作RabbitMq
Python selenium绕过webdriver监测执行javascript
Apr 12 #Python
Pillow图像处理库安装及使用
Apr 12 #Python
Python各协议下socket黏包问题原理
Apr 12 #Python
You might like
模拟OICQ的实现思路和核心程序(一)
2006/10/09 PHP
木翼下载系统中说明的PHP安全配置方法
2007/06/16 PHP
php5中date()得出的时间为什么不是当前时间的解决方法
2008/06/30 PHP
PHP加速 eAccelerator配置和使用指南
2009/06/05 PHP
PHP中的函数嵌套层数限制分析
2011/06/13 PHP
PHP 类相关函数的使用详解
2013/05/10 PHP
叫你如何修改Nginx与PHP的文件上传大小限制
2014/09/10 PHP
php使用fputcsv实现大数据的导出操作详解
2020/02/27 PHP
javascript FormatNumber函数实现方法
2008/12/30 Javascript
将input file的选择的文件清空的两种解决方案
2013/10/21 Javascript
页面加载完后自动执行一个方法的js代码
2014/09/06 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
2016/01/08 Javascript
JavaScript+html5 canvas制作的百花齐放效果完整实例
2016/01/26 Javascript
JS常用函数和常用技巧小结
2016/10/15 Javascript
jQuery无缝轮播图代码
2016/12/22 Javascript
JavaScript变量作用域_动力节点Java学院整理
2017/06/27 Javascript
jqgrid实现简单的单行编辑功能
2017/09/30 Javascript
js+canvas实现验证码功能
2020/09/21 Javascript
手把手教你使用TypeScript开发Node.js应用
2019/05/06 Javascript
vue使用一些外部插件及样式的配置代码
2019/11/18 Javascript
使用Python进行新浪微博的mid和url互相转换实例(10进制和62进制互算)
2014/04/25 Python
使用python对文件中的单词进行提取的方法示例
2018/12/21 Python
如何通过python实现全排列
2020/02/11 Python
阻止移动设备(手机、pad)浏览器双击放大网页的方法
2014/06/03 HTML / CSS
澳大利亚优质的家居用品和生活方式公司:Bed Bath N’ Table
2019/04/16 全球购物
物业管理个人自我评价
2013/11/08 职场文书
幼儿园中秋节活动方案
2014/02/06 职场文书
大学军训感言400字
2014/03/11 职场文书
开业典礼主持词
2014/03/21 职场文书
安全生产演讲稿
2014/05/09 职场文书
中国梦演讲稿3分钟
2014/08/19 职场文书
2014年药店店长工作总结
2014/11/17 职场文书
小学生安全保证书
2015/05/09 职场文书
个人催款函范文
2015/06/24 职场文书
解决python绘图使用subplots出现标题重叠的问题
2021/04/30 Python
Python中生成随机数据安全性、多功能性、用途和速度方面进行比较
2022/04/14 Python