目录
一、架构介绍二、安装创建和启动三、配置文件目录介绍四、爬取数据,并解析五、数据持久化保存到文件保存到redis保存到MongoDB保存到mysql六、动作链,控制滑动的验证码七、提高爬取效率八、fake-useragent池九、中间件配置process_exception 错误处理process_request 加代理,加cookie等十、集成selenium十一、指纹和布隆过滤器实现增量爬取网址指纹布隆过滤器十二、分布式爬虫十三、爬虫框架全站爬取使用案例一、架构介绍
Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。整体架构大致如下
IO多路复用
# 引擎(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)
四、爬取数据,并解析
# 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 = { ".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及详细讲解的详细内容,更多关于scarpy爬虫框架结构集成selenium的资料请关注脚本之家其它相关文章!
X 关闭
X 关闭
- 15G资费不大降!三大运营商谁提供的5G网速最快?中国信通院给出答案
- 2联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 3亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 4现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 5如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 6AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 7转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 8充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 9好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 10名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?