# Linux
pip3 install scrapy
# windows版本
1.pip install wheel
2.下载
https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
pip install C:\Users\Administrator\Desktop\lxml-4.4.1-cp37-cp37m-win_amd64.whl
3.下载
https://www.lfd.uci.edu/~gohlke/pythonlibs/#Twisted
pip install C:\Users\Administrator\Desktop\Twisted-19.10.0-cp37-cp37m-win_amd64.whl
4.下载 (一定要下对应版本)
https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/
安装(无脑下一步)
5.pip install scrapy
------------------
#设置settings.py
------
FEED_EXPORT_ENCODING = 'utf-8' #'GB2312' #设置编码
DEPTH_LIMIT=1 #设置调度器遍历层级
ROBOTSTXT_OBEY = False # 是否遵行robots协议,设置False允许爬取所有,默认为True,表示遵守
# USER_AGENT 是伪装访问者信息
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
DOWNLOAD_DELAY = 3 #请求延迟,多少秒执行一次
COOKIES_ENABLED = True #是否拿到cookie,默认是True
#设置请求限速
AUTOTHROTTLE_ENABLED = True #自动限速扩展(实现上一个请求和下一个请求的时间是不固定的,默认为False
AUTOTHROTTLE_START_DELAY = 5 #初始的下载延时默认5秒
AUTOTHROTTLE_MAX_DELAY = 60 #最大下载延时
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 #针对网站最大的并行请求数量
AUTOTHROTTLE_DEBUG = False #调试模式(可以展示每个response每个限速时间)默认为False
#设置缓存
HTTPCACHE_ENABLED = True #是否启用缓存
HTTPCACHE_EXPIRATION_SECS = 0 #设置超时时间
HTTPCACHE_DIR = 'httpcache' #缓存路径
HTTPCACHE_IGNORE_HTTP_CODES = [] #缓存忽略的http状态码
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' #缓存启用插件
--------
#创建项目
scrapy startproject app
#创建起始文件
scrapy genspider chouti dig.chouti.com # chouti名字 dig.chouti.com 网址
#运行
scrapy crawl chouti --nolog #加--nolog不显示日志 chouti名字
-----
chouti.py
---------
from scrapy.selector import Selector
from scrapy.http import Request
from ..items import ChoutiItem # 使用pipeline做缓存,持久化
class ChoutiSpider(scrapy.Spider):
name = 'chouti' #不能省略,是运行命令的名字
allowed_domains = ['www.htqyy.com'] #允许的域名
start_urls = ['http://www.htqyy.com/genre/11'] #起始地址
#def start_request(self): #可以重写初始请求
# for url in self.start_urls:
# yield Request(url,callback=self.parse)
def parse(self, response):
hxs=Selector(response=response).xpath('//a[@class="link"]').extract() # .extract()获取内容,默认是类
for i in hxs:
print(i)
def next_page(self,url):
# 将新要访问的url添加到调度器(固定语法)
yield Request(url=url,callback=self.getName)
def getName(self, response):
hxs=Selector(response=response).xpath('//script[@type="text/javascript"]/text()').extract()
for v in hxs:
url=re.search(r"var name = [\"\'](.+?)[\"\']"v,re.S)
if url:
name=url.group(1)
item_obj = ChoutiItem(name=name) # 配置pipeline缓存字段
yield item_obj
------------------------------
items.py # 配置pipeline缓存字段
-----
import scrapy
import scrapy.http.Cookies import CookieJar #获取设置cookie用
class ChoutiItem(scrapy.Item):
name = scrapy.Field() #缓存字段
#def parse(self,response):
# cookie_obj=CookieJar()
# cookie_obj.extract_cookies(response,response.request)
# print(cookie_obj._cookies) #获取所有cookies
-----
setttings.py 添加要使用的pipeline缓存
----
ITEM_PIPELINES = {
'app.pipelines.AppPipeline': 200, #那个值小先执行那个
'app.pipelines.AppPipeline2': 300,
}
注:配置里变量都需要大写否则读取不到
----
pipelines.py 使用缓存
---------
class AppPipeline(object):
def __init__(self,conn_str):
self.conn_str=conn_str
@classmethod
def from_crawler(cls,crawler):
#初始化用于创建pipline对象,并读取配置文件
val=crawler.settings.getint('xxx') #获取settings.py配置信息
return cls(val) #相当于调用 __init__
def open_spider(self, spider):
#爬虫开始时被调用
def clese_spider(self, spider):
#爬虫关闭时被调用
def process_item(self, item, spider):
#每当数据需要持久化时,被调用(每次缓存都调用)
print("da=>",item.get('name'))
#加return item 会执行下个AppPipeline2不加不执行
#return item
class AppPipeline2(object):
...
------------
# 请求对象
from scrapy.http import Request
Request(url, #请求的URL
callback=self.getName, #请求的响应回调,下载内容为第一个参数
method ='GET', #请求方法,默认为'GET',要大写的
headers = {}, #请求头,字典格式
body = None, #包含请求主体的str
Cookies = {}, # {}或[{},{}] 请求cookie
meta = {'data':111}, #设置携带的参数,可以通过response拿到
encoding ='utf-8', #请求的编码(默认为'utf-8')
priority = 0, #请求的优先级(默认为0),较高值优先
dont_filter = False,
errback = self.getName, #异常回调,第一个参数为错误信息
flags = None,
cb_kwargs = None)
----------
# response 响应参数
def getName(self, response):
参数:
response.meta.get('data') #获取携带的参数
response.url #请求地址
response.text #响应主体,为unicode
response.body #始终是一个字节对象
response.meta={'depth':1} #depth 响应深度
response.status #响应的HTTP状态
response.headers #响应头
-----------
# 采集html数据 xpath 两种方式
from scrapy.selector import Selector
Selector(response=response).xpath('//title/text()').extract() #老版方式
response.xpath('//title/text()').extract() #直接响应里取
# xpath('//') 选择器:
----
// 表示子孙中
.// 当前对象的子孙中
/ 儿子
/div 儿子中的div标签
/div[2] 儿子中的div第二个标签
/div[@id] 儿子中的div标签有id的
/div[@id="i1"] 儿子中的div标签且id=i1
/div[@id="i1"] 儿子中的div标签且id=i1
obj.extract() # 列表中的每一个对象转换字符串 =》 []
obj.extract_first() # 列表中的每一个对象转换字符串 => 列表第一个元素
//div/text() 获取某个标签的文本
a/@href 获取属性
//a[starts-with(@href, "/all/hot/recent/")]/@href' 已xx开始
//a[re:test(@href, "/all/hot/recent/\d+")] 正则
----------
#设置代理ip
-----
1.项目根目录下面创建了一个myproxy.py的文件用于存放自定义的代理相关的类。
import random,base64
def to_bytes(text, encoding=None, errors='strict'):
if isinstance(text, bytes):
return text
if not isinstance(text, six.string_types):
raise TypeError('to_bytes must receive a unicode, str or bytes '
'object, got %s' % type(text).__name__)
if encoding is None:
encoding = 'utf-8'
return text.encode(encoding, errors)
class OneProxyMiddleware(object):
def process_request(self, request, spider):
PROXIES = [
{'ip_port': '111.11.228.75:80', 'user_pass': ''},
{'ip_port': '120.198.243.22:80', 'user_pass': ''},
{'ip_port': '111.8.60.9:8123', 'user_pass': ''},
{'ip_port': '101.71.27.120:80', 'user_pass': ''},
{'ip_port': '122.96.59.104:80', 'user_pass': ''},
{'ip_port': '122.224.249.122:8088', 'user_pass': ''},
]
proxy = random.choice(PROXIES)
if proxy['user_pass'] is not None:
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])
encoded_user_pass = base64.b64encode(to_bytes(proxy['user_pass']))
request.headers['Proxy-Authorization'] = to_bytes('Basic ' + encoded_user_pass)
else:
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])
2.settings.py里面添加扩展
DOWNLOADER_MIDDLEWARES = {
'app.myproxy.MyProxyMiddleware': 100
}
------
#https自定义证书
------
Https访问时有两种情况:
1.要爬取网站使用的可信任证书(默认支持)
DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY = "scrapy.core.downloader.contextfactory.ScrapyClientContextFactory"
2.要爬取网站使用的自定义证书
DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY = "app.https.MySSLFactory"
# https.py
from scrapy.core.downloader.contextfactory import ScrapyClientContextFactory
from twisted.internet.ssl import (optionsForClientTLS, CertificateOptions, PrivateCertificate)
class MySSLFactory(ScrapyClientContextFactory):
def getCertificateOptions(self):
from OpenSSL import crypto
# open('/Users/... 放配置文件的目录
v1 = crypto.load_privatekey(crypto.FILETYPE_PEM, open('/Users/client.key.unsecure', mode='r').read())
v2 = crypto.load_certificate(crypto.FILETYPE_PEM, open('/Users/client.pem', mode='r').read()) #读取配置文件
return CertificateOptions(
privateKey=v1, # pKey对象
certificate=v2, # X509对象
verify=False,
method=getattr(self, 'method', getattr(self, '_ssl_method', None))
)
--------
#做定时任务
----------
1.最简单的方法:直接使用Timer类
import time
import os
while True:
os.system("scrapy crawl chouti --nolog")
time.sleep(86400) #每隔一天运行一次 24*60*60=86400s
2.使用标准库的sched模块
import sched
#初始化sched模块的scheduler类
#第一个参数是一个可以返回时间戳的函数,第二个参数可以在定时未到达之前阻塞。
schedule = sched.scheduler ( time.time, time.sleep )
#被周期性调度触发的函数
def func():
os.system("scrapy crawl News")
def perform1(inc):
schedule.enter(inc,0,perform1,(inc,))
func() # 需要周期执行的函数
def mymain():
schedule.enter(0,0,perform1,(86400,))
if __name__=="__main__":
mymain()
schedule.run() # 开始运行,直到计划时间队列变成空为止