Scrapy學習筆記(7)-定制動態可配置爬蟲

前言

????最近一直想維護一個代理IP池,在網上找了三十多個免費提供代理IP的網站,想把這些代理都抓取下來存到本地數據庫,再寫一個守護進程定時去驗證可用性和連接速度,剔除失效代理,以此來保證庫里面始終都有特定數量的優質代理IP。那么問題來了,這么多網站每個網站的頁面布局或者說網頁源碼都不一樣,數據抓取規則也不一樣,如果針對每個網站都硬編碼一份spider代碼,這工作量貌似有點大,而且一旦目標站點調整布局,我們之前寫好的spider代碼很可能就得再次修改。此時我迫切地希望能有一個框架可以通過只寫一份spider代碼和維護多個網站的爬取規則,就能自動抓取這些網站的信息,很慶幸的是強大的Scrapy?可以做到這點,本文記錄實現過程。

技術點

1.根據爬取規則自動生成spider

2.使用Scrapy核心API操作spider

3.Linux下Redis的安裝和使用

4.基于Redis和SQLAlchemy對Scrapy Item去重并存儲

實現過程

????筆者系統為centos,關于Redis的安裝和配置可以參考這里:http://jinbitou.net/2016/10/28/2110.html,windows環境的讀者請自行Google。本次項目的目錄結構如下:

主要文件和目錄解釋:

model目錄存放的是數據庫表的映射文件

spiders目錄存放的是spider代碼

initDB.py是用來初始化數據庫的,自動根據model目錄下的映射文件在數據庫中建好相應的表

pipelines.py實現將抓取到的數據持久化到數據庫

proxy_middlewares.py自定義中間件,用來設定代理IP

useragent_middlewares.py自定義中間件,用來隨機切換UA

run.py總控腳本,從規則表中讀取規則,動態生成spider并啟動

廢話不多說,上代碼!

__init__.py(文件1)

# -*- coding: utf-8 -*-from sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmaker# 創建對象的基類:Base = declarative_base()# 初始化數據庫連接:engine = create_engine('mysql+mysqldb://root:123456@localhost:3306/scrapy?charset=utf8')#返回數據庫會話def loadSession():? ? Session = sessionmaker(bind=engine)? ? session = Session()? ? return session

proxy.py(文件2)

from sqlalchemy import Column,String,Integer,DateTimefrom . import Baseimport datetimeclass Proxy(Base):#繼承Base類? ? __tablename__ = 'proxies'? ? ip_port= Column(String(30),primary_key=True,nullable=False)#主鍵? ? type= Column(String(20),nullable=True,default="")#協議類型? ? level= Column(String(20),nullable=True,default="")#匿名級別? ? location= Column(String(100),nullable=True,default="")#ip所在地區? ? speed= Column(String(20),nullable=True,default="")#連接速度? ? lifetime = Column(String(20),nullable=True,default="")#生存時間? ? lastcheck = Column(String(20),nullable=True,default="")#最后校驗時間? ? source = Column(String(500), nullable=False)#頁面地址? ? rule_id = Column(Integer,nullable=False)#規則(網站/spider)id? ? indate = Column(DateTime,nullable=False)#入庫時間? ? def __init__(self,ip_port,source,type,level,location,speed,lifetime,lastcheck,rule_id):? ? ? ? self.ip_port=ip_port

? ? ? ? self.type=type

? ? ? ? self.level=level

? ? ? ? self.location=location

? ? ? ? self.speed=speed

? ? ? ? self.source=source

? ? ? ? self.lifetime=lifetime

? ? ? ? self.lastcheck=lastcheck

? ? ? ? self.rule_id=rule_id

? ? ? ? self.indate=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

rules.py(文件3)

# -*- coding: utf-8 -*-from sqlalchemy import Column,String,Integerfrom sqlalchemy import Sequencefrom . import Baseclass Rule(Base):? ? __tablename__ = 'rules'? ? # 表結構:? ? id = Column(Integer, Sequence('id',start=1,increment=1),primary_key=True)#設定自增長主鍵? ? name = Column(String(100),nullable=False)#spider的名字? ? allowed_domains = Column(String(500),nullable=False)#允許爬取的域? ? start_urls = Column(String(500),nullable=False)#開始爬取的入口? ? next_page = Column(String(500),nullable=False,default="")#xpath表達式,爬取下一頁? ? allow_url = Column(String(500),nullable=False)#正則表達式,匹配符合要求的鏈接? ? extract_from = Column(String(500),nullable=False,default="")#xpath表達式,限制解析區域? ? loop_xpath = Column(String(500),nullable=False)#xpath表達式,控制單頁面循環次數? ? ip_xpath = Column(String(500),nullable=False)#xpath表達式,解析IP? ? port_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析端口? ? location1_xpath = Column(String(500),nullable=False)#xpath表達式,解析區域? ? location2_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析區域? ? speed_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析連接速度? ? lifetime_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析生存時間? ? type_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析協議類別? ? level_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析匿名級別? ? lastcheck_xpath = Column(String(500),nullable=False,default="")#xpath表達式,解析最后校驗時間? ? enable = Column(Integer,nullable=False)#激活rule的開關,1為開0為關

proxy_spider.py(文件4)

# -*- coding: utf-8 -*-import scrapyfrom scrapy.linkextractors import LinkExtractorfrom scrapy.spiders import CrawlSpider, Rule#抓取信息的數據結構,類似于javabeanclass IpProxyPoolItem(scrapy.Item):? ? ip_port = scrapy.Field()? ? type = scrapy.Field()? ? level = scrapy.Field()? ? location = scrapy.Field()? ? speed = scrapy.Field()? ? lifetime = scrapy.Field()? ? lastcheck = scrapy.Field()? ? rule_id = scrapy.Field()? ? source = scrapy.Field()#搭建spider的主體框架,繼承CrawlSpider類class ProxySpiderSpider(CrawlSpider):? ? name = 'MagicSpider'? ? def __init__(self,rule):? ? ? ? self.rule = rule

? ? ? ? self.name = rule.name

? ? ? ? #spilt函數通過分隔符分割字符串,得到列表類型? ? ? ? self.allowed_domains = rule.allowed_domains.split(',')? ? ? ? self.start_urls = rule.start_urls.split(',')? ? ? ? rule_list = []? ? ? ? # 添加"下一頁"鏈接的規則? ? ? ? if len(rule.next_page):? ? ? ? ? ? rule_list.append(Rule(LinkExtractor(restrict_xpaths=rule.next_page), follow=True))? ? ? ? #鏈接提取規則? ? ? ? rule_list.append(Rule(LinkExtractor(? ? ? ? ? ? allow=rule.allow_url.split(','),? ? ? ? ? ? unique=True),#鏈接去重? ? ? ? ? ? follow=True,#跟隨爬取? ? ? ? ? ? callback='parse_item'))#調用parse_item提取數據? ? ? ? #使用tuple()將列表轉換為元組? ? ? ? self.rules = tuple(rule_list)? ? ? ? #當有子類繼承ProxySpiderSpider的時候,調用初始化方法啟動爬取過程? ? ? ? super(ProxySpiderSpider, self).__init__()? ? def parse_item(self, response):? ? ? ? item=IpProxyPoolItem()? ? ? ? if len(self.rule.loop_xpath):? ? ? ? ? ? for proxy in response.xpath(self.rule.loop_xpath):? ? ? ? ? ? ? ? if len(self.rule.ip_xpath):? ? ? ? ? ? ? ? ? ? tmp_ip = proxy.xpath(self.rule.ip_xpath).extract_first()? ? ? ? ? ? ? ? ? ? #strip函數用來刪除空白字符(包括'\n', '\r',? '\t',? ' ')? ? ? ? ? ? ? ? ? ? ip = tmp_ip.strip() if tmp_ip is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? ip = ""? ? ? ? ? ? ? ? if len(self.rule.port_xpath):? ? ? ? ? ? ? ? ? ? tmp_port = proxy.xpath(self.rule.port_xpath).extract_first()? ? ? ? ? ? ? ? ? ? port = tmp_port.strip() if tmp_port is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? port = ""? ? ? ? ? ? ? ? if len(self.rule.location1_xpath):? ? ? ? ? ? ? ? ? ? tmp_location1 = proxy.xpath(self.rule.location1_xpath).extract_first()? ? ? ? ? ? ? ? ? ? location1 = tmp_location1.strip() if tmp_location1 is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? location1 = ""? ? ? ? ? ? ? ? if len(self.rule.location2_xpath):? ? ? ? ? ? ? ? ? ? tmp_location2 = proxy.xpath(self.rule.location2_xpath).extract_first()? ? ? ? ? ? ? ? ? ? location2 = tmp_location2.strip() if tmp_location2 is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? location2 = ""? ? ? ? ? ? ? ? if len(self.rule.lifetime_xpath):? ? ? ? ? ? ? ? ? ? tmp_lifetime = proxy.xpath(self.rule.lifetime_xpath).extract_first()? ? ? ? ? ? ? ? ? ? lifetime = tmp_lifetime.strip() if tmp_lifetime is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? lifetime = ""? ? ? ? ? ? ? ? if len(self.rule.lastcheck_xpath):? ? ? ? ? ? ? ? ? ? tmp_lastcheck = proxy.xpath(self.rule.lastcheck_xpath).extract_first()? ? ? ? ? ? ? ? ? ? lastcheck = tmp_lastcheck.strip() if tmp_lastcheck is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? lastcheck = ""? ? ? ? ? ? ? ? if len(self.rule.level_xpath):? ? ? ? ? ? ? ? ? ? tmp_level = proxy.xpath(self.rule.level_xpath).extract_first()? ? ? ? ? ? ? ? ? ? level = tmp_level.strip() if tmp_level is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? level = ""? ? ? ? ? ? ? ? if len(self.rule.type_xpath):? ? ? ? ? ? ? ? ? ? tmp_type = proxy.xpath(self.rule.type_xpath).extract_first()? ? ? ? ? ? ? ? ? ? type = tmp_type.strip() if tmp_type is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? type = ""? ? ? ? ? ? ? ? if len(self.rule.speed_xpath):? ? ? ? ? ? ? ? ? ? tmp_speed = proxy.xpath(self.rule.speed_xpath).extract_first()? ? ? ? ? ? ? ? ? ? speed = tmp_speed.strip() if tmp_speed is not None else ""? ? ? ? ? ? ? ? else:? ? ? ? ? ? ? ? ? ? speed = ""? ? ? ? ? ? ? ? #join函數用來拼接字符串,接收的參數為列表類型? ? ? ? ? ? ? ? item['ip_port']=(":".join([ip,port])) if len(port) else ip

? ? ? ? ? ? ? ? item['type']=type

? ? ? ? ? ? ? ? item['level']=level

? ? ? ? ? ? ? ? item['location']=(" ".join([location1,location2])) if location2 is not None and len(location2) else location1

? ? ? ? ? ? ? ? item['speed']=speed

? ? ? ? ? ? ? ? item['lifetime']=lifetime

? ? ? ? ? ? ? ? item['lastcheck']=lastcheck

? ? ? ? ? ? ? ? item['rule_id']=self.rule.id

? ? ? ? ? ? ? ? item['source']=response.url

? ? ? ? ? ? ? ? yield item

pipelines.py(文件6)

# -*- coding: utf-8 -*-import MySQLdbfrom scrapy.exceptions import DropItemimport redisfrom model import loadSessionfrom model import proxyfrom scrapy import logimport loggingRedis = redis.StrictRedis(host='localhost',port=6379,db=0)# item去重class DuplicatesPipeline(object):? ? def process_item(self, item, spider):? ? ? ? if Redis.exists('ip_port:%s' % item['ip_port']) :? ? ? ? ? ? raise DropItem("Duplicate item found: %s" % item)? ? ? ? else:? ? ? ? ? ? Redis.set('ip_port:%s' % item['ip_port'],1)? ? ? ? ? ? return item#數據入庫class IpProxyPoolPipeline(object):? ? def process_item(self, item, spider):? ? ? ? if len(item['ip_port']):? ? ? ? ? ? a = proxy.Proxy(? ? ? ? ? ? ? ? ip_port=item['ip_port'],? ? ? ? ? ? ? ? type=item['type'],? ? ? ? ? ? ? ? level=item['level'],? ? ? ? ? ? ? ? location=item['location'],? ? ? ? ? ? ? ? speed=item['speed'],? ? ? ? ? ? ? ? lifetime=item['lifetime'],? ? ? ? ? ? ? ? lastcheck=item['lastcheck'],? ? ? ? ? ? ? ? rule_id=item['rule_id'],? ? ? ? ? ? ? ? source=item['source']? ? ? ? ? ? )? ? ? ? ? ? session = loadSession()? ? ? ? ? ? try:? ? ? ? ? ? ? ? session.merge(a)? ? ? ? ? ? ? ? session.commit()? ? ? ? ? ? except MySQLdb.IntegrityError, e:? ? ? ? ? ? ? ? log.msg("MySQL Error: %s" % str(e), _level=logging.WARNING)? ? ? ? ? ? return item

? ? ? ? else:? ? ? ? ? ? log.msg("ip_port is invalid!",_level=logging.WARNING)

proxy_middlewares.py(文件7)

# -*- coding: utf-8 -*-import randomfrom scrapy import logimport loggingclass ProxyMiddleware(object):? ? proxyList = [ \

? ? ? ? '124.88.67.18:80',? ? ? ? '124.88.67.52:843',? ? ? ? '110.77.169.30:8080',? ? ? ? '58.246.194.70:8080',? ? ? ? '159.232.214.68:8080'? ? ? ? ]? ? def process_request(self, request, spider):? ? ? ? # 從代理IP列表中隨機選擇一個? ? ? ? pro_adr = random.choice(self.proxyList)? ? ? ? log.msg("Current Proxy <%s>" % pro_adr,_level=logging.INFO)? ? ? ? request.meta['proxy'] = "http://" + pro_adr

useragent_middlewares.py(文件9)

# -*-coding:utf-8-*-from scrapy import logimport logging'''

#避免被ban策略之一:使用useragent池。

'''import randomfrom scrapy.downloadermiddlewares.useragent import UserAgentMiddlewareclass UserAgent(UserAgentMiddleware):? ? def __init__(self, user_agent=''):? ? ? ? self.user_agent = user_agent

? ? def process_request(self, request, spider):? ? ? ? ua = random.choice(self.user_agent_list)? ? ? ? if ua:? ? ? ? ? ? #顯示當前使用的useragent? ? ? ? ? ? #print "********Current UserAgent:%s************" %ua? ? ? ? ? ? #記錄? ? ? ? ? ? log.msg('Current UserAgent: '+ua, _level=logging.INFO)? ? ? ? ? ? request.headers.setdefault('User-Agent', ua)? ? user_agent_list = [\

? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "? ? ? ? "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",? ? ? ? "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "? ? ? ? "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "? ? ? ? "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",? ? ? ? "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "? ? ? ? "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",? ? ? ? "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "? ? ? ? "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",? ? ? ? "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",? ? ? ? "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",? ? ? ? "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",? ? ? ? "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",? ? ? ? "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",? ? ? ? "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50"? ? ? ? "(KHTML, like Gecko) Version/5.1 Safari/534.50",? ? ? ? "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50"

? ? ? ? "(KHTML, like Gecko) Version/5.1 Safari/534.50",? ? ? ? "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",? ? ? ? "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0;"? ? ? ? ".NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko",? ? ? ? "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 "? ? ? ? "(KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",? ? ? ? "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",? ? ? ? "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; "? ? ? ? "AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",? ? ? ? "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; "? ? ? ? "Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",? ? ? ? "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; "? ? ? ? "AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",? ? ? ? "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",? ? ? ? "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; "? ? ? ? "Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",? ? ? ? "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; "? ? ? ? "Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",? ? ? ? "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; "? ? ? ? "InfoPath.2; .NET CLR 3.0.04506.30)",? ? ? ? "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 "? ? ? ? "(KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",? ? ? ? "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",? ? ? ? "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",? ? ? ? "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",? ? ? ? "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",? ? ? ? "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",? ? ? ? "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",? ? ? ? "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 "? ? ? ? "(KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",? ? ? ? "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52"? ? ? ]

initDB.py(文件5)

初始化數據庫,自動建好所需的數據庫表,并添加了一條規則# -*- coding: utf-8 -*-from model import loadSessionfrom model import proxyfrom model.rules import Rulefrom model import Base,engine#尋找Base的所有子類,并在數據庫中生成表Base.metadata.create_all(engine)#返回數據庫會話session = loadSession()#實例化一個Rule對象item=Rule()item.name="ip84"item.allowed_domains="ip84.com"item.start_urls="http://ip84.com/gn/1"item.next_page="http://a[@class='next_page']"item.allow_url="/gn/\d+"item.loop_xpath="http://table[@class='list']/tr[position()>1]"item.ip_xpath="td[1]/text()"item.port_xpath="td[2]/text()"item.location1_xpath="td[3]/a[1]/text()"item.location2_xpath="td[3]/a[2]/text()"item.speed_xpath="td[6]/text()"item.type_xpath="td[5]/text()"item.level_xpath="td[4]/text()"item.enable="1"#添加到數據庫session.add(item)session.commit()

run.py(文件8)

# -*- coding: utf-8 -*-from spiders.proxy_spider import ProxySpiderSpiderfrom model import loadSessionfrom model.rules import Rulefrom scrapy.crawler import CrawlerProcessfrom scrapy.settings import Settings#spider相關設置settings = Settings()'''

Scrapy框架的高度靈活性得益于其數據管道的架構設計,開發者可以通過簡單的配置就能輕松地添加新特性。

我們可以通過如下的方式添加pipline。

'''settings.set("ITEM_PIPELINES" , {? ? 'pipelines.DuplicatesPipeline': 200,? ? 'pipelines.IpProxyPoolPipeline': 300,})#設置默認請求頭settings.set("DEFAULT_REQUEST_HEADERS",{? 'Accept': 'text/html, application/xhtml+xml, application/xml',? 'Accept-Language': 'zh-CN,zh;q=0.8'})#注冊自定義中間件,激活切換UA的組件和切換代理IP的組件settings.set("DOWNLOADER_MIDDLEWARES",{? 'useragent_middlewares.UserAgent': 1,? 'proxy_middlewares.ProxyMiddleware':100,? 'scrapy.downloadermiddleware.useragent.UserAgentMiddleware' : None,})#設置爬取間隔settings.set("DOWNLOAD_DELAY",1)#禁用cookiessettings.get("COOKIES_ENABLED",False)#設定是否遵循目標站點robot.txt中的規則settings.get("ROBOTSTXT_OBEY",True)#加載設置process = CrawlerProcess(settings)session=loadSession()#取出規則表中已激活的rulerules = session.query(Rule).filter(Rule.enable == 1)for rule in rules:? ? process.crawl(ProxySpiderSpider,rule)process.start()

開始爬取

shell中執行python run.py即可開始采集數據…

新增兩個網站的爬取規則:

http://www.xicidaili.com/

http://www.kuaidaili.com/free/

檢驗結果:

三條規則生成的spider在兩個小時不到已經采集了6萬多IP。

更多原創文章,盡在金筆頭博客

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容