Scrapy教程

基础

1、创建一个项目

	scrapy startproject mySpider

2、新建一个爬虫

2、新建一个爬虫

scrapy genspiders spiders 
import scrapy
class SpidersSpider(scrapy.Spider):
    name = 'spiders'  # 爬虫名
    allowed_domains = ['itcast.cn']  # 允许爬虫的范围
    start_urls = ['http://itcast.cn/']  # 最开始请求的url的地址

    def parse(self, response):
          # 处理start_urls 地址对应的响应
        li_list = response.xpath('//div[@class="tea_con"]')
        for li in li_list:
            item = {
     }
            item['name'] = li.xpath(".//h3/text()").extract_first()
            item['title'] = li.xpath(".//h4/text()").extract_first()
        # res = response.xpath('//div[@class="tea_con"]//h3/text()').extract_first()
        # print(res)
        yield item  # 把列表传到piplines中
注:xpath写错会默认给提供None值

3、启动爬虫

3、启动爬虫

scrapy crwal spiders

在/settings下的设置里面

LOG_LEVEL = "WARNING"
控制台只显示warning以上水平的信息

4、pipline[管道]处理

4、pipline[管道]处理

/parse()下:
yield item  # 把列表传到piplines中
首先:settings中把注释的piplines取消注释

/settings下
ITEM_PIPELINES = {
     
   'myspider.pipelines.MyspiderPipeline': 300,  # 数据越小,越先执行
   'myspider.pipelines.MyspiderPipeline1': 301,  # 数据越小,越先执行
}
/piplines下
定义两个pipline类 
class MyspiderPipeline:
    def process_item(self, item, spider):
        print(item)
        item["hello"] = 'word'
        return item

class MyspiderPipeline1:
    def process_item(self, item, spider):
        print(item)
        return item
   
 执行结果:
{
     'name': '黄老师', 'title': '高级讲师'}
{
     'name': '黄老师', 'title': '高级讲师', 'hello': 'word'}

5、如何区别多个爬虫的pipline

5、如何区别多个爬虫的pipline

方式一:
 def parse(self, response):
    item = {
     }
    item["come_from"] = 'itcast'

class MyspiderPipeline:
    def process_item(self, item, spider):
        if item['come_from'] == 'itcast':
            print(item)
            item["hello"] = 'word'
            return item

方式二【推荐】:
class MyspiderPipeline:
    def process_item(self, item, spider):
        if spider.name == 'itcast':

6、logging输出

6、logging输出

import logging
logger = logging.getLogger(__name__)  # 能输出当前日志的输出

/setting下
LOG_LEVEL = "WARNING"
LOG_FILE = "./log.log"  #  将日志保存到本地

7、logging 非scrapy 输出

7、logging   非scrapy 输出

import logging
logging.basicConfig(level=logging.DEBUG,
          format='%(levelname)s %(filename)s '
              '%(message)s'
              ' - %(asctime)s', datefmt='[%d/%b/%Y %H:%M:%S]',
          filename='./loggmsg.log', filemode="a")
logger = logging.getLogger(__name__)

8、实现翻页

8、实现翻页
next_page_url = response.xpath("//a[text()='下一页']/@href).extract()

while len(next_page_url)>0:
	yield scrapy.Request(next_page_url, callback=self.parse)

9、yield scrapy.Request()使用介绍

#9yield scrapy.Request()使用介绍

yield scrapy.Request(url, 
callback,  # 指定传入的url交给哪个解析函数去处理
method='POST',
headers,
body,
cookies,
meta, # 实现在不同的解析函数中传递数据,meta默认会携带部分信息
dont_filter=False,
)
上注:
meta:实现在不同的解析函数中传递数据,meta默认会携带部分信息
例:
yield scrapy.Request(next_page_url, callback=self.parse1
meta = {
     'item': item}
)
def paras1(self, response)
	response.meta['item'] #在此取到上面出来的item

dont_filter=False: 让scrapy的去重不会过滤当前url,scrapy默认有url去重功能,对需要重复请求的url有重要用途

10、数据处理(去空白,/s /t 空字符串)

列表表达式:
item = ['http://url'+i for i in item['url']


piplines.py 下
def process_conent(self, content):
	content = [re.sub(r"\xa0|\s|\t","", i) for i in content]
	content = [i for i in content if len(i)>0]
	# 去除列表中的字符串

11、scrapy sell

scrapy shell https://www.baidu.com
可以进一步查看请求和响应信息
response.url: 当前响应的网址
response.request.url: 当前响应对应请求的url地址
response.headers: 请求头
response.body: 响应体
response.request.headers:当前响应的请求头

12、settings深入

# Configure maximum concurrent requests performed by Scrapy (default: 16) 最大并发请求
#CONCURRENT_REQUESTS = 32


#下载延迟,每次下载等三秒
#DOWNLOAD_DELAY = 3 


# Disable cookies (enabled by default)
# 是否开启cookie,默认情况是开启的。
# COOKIES_ENABLED = False


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


#自动限速
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
# AUTOTHROTTLE_ENABLED = True


http缓存
# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
# HTTPCACHE_ENABLED = True
# HTTPCACHE_EXPIRATION_SECS = 0
# HTTPCACHE_DIR = 'httpcache'
# HTTPCACHE_IGNORE_HTTP_CODES = []
# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'


主程序中使用settings中的内容:
self.settings.get('HTTPCACHE_ENABLED ')

13、pipline使用

import json
class JsonWriterPipline(object):	
	#在爬虫开启的时候,仅执行一次
	def open_spider(self, spider):
		self.file = open(spider.settings.get("SAVE_FILE","./item.json"),"w")
	#在爬虫结束的时候,仅执行一次
	def close_spider(self, spider):
		self.file.close()
	def process_item(self, item, spider):
		line = json.dumps(dict(item))+ "\n"
		self.file.wirte(line)
		return item
		#不return的情况下,另一个权重较低的pipline就不会获取到该item

爬去糗事百科示例

1.settings下:

# Obey robots.txt rules 不遵循网站的机器规则
ROBOTSTXT_OBEY = False

# Override the default request headers: 设置默认请求头
DEFAULT_REQUEST_HEADERS = {
     
    'Accept'         : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    'User-Agent'     : 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
}

2、将数据保存到duanzi.json文件中

class QsbkPipeline:
    def __init__(self):
        self.fp = open('duanzi.json', 'w', encoding='utf-8')
        
    # 爬虫开始前调用open_spider
    def open_sipder(self, spider):
        print('这是爬虫开始。。')
    
    def process_item(self, item, spider):
         item_json = json.dumps(item, ensure_ascii=False)
        self.fp.write(item_json + '\n')
        return item
    
    # 爬虫结束前调用close_spider
    def close_spider(self, spider):
        print('这是爬虫结束。。')

注意:settings中打开
ITEM_PIPELINES = {
     
   'qsbk.pipelines.QsbkPipeline': 300,
}

3、保存数据写法优化

items下:定义两个字段
import scrapy
class QsbkItem(scrapy.Item):
    author = scrapy.Field()
    content = scrapy.Field()

spider下:
from  items import QsbkItem
 text_dict = QsbkItem(author=author, content=content)
 yield text_dict

piplins下:
 item_json = json.dumps(dict(item), ensure_ascii=False)
 self.fp.write(item_json + '\n')
 return item

笔记:

1. response是一个'scrapy,http.response.html.HtmlResponse'对象,可直接执行'xapth', 'css'语法来提取数据。
2. 提取出来的数据,是一个Selector或者是一个SelectorLIst对象。想要获取其中的字符串,那么应该执行"get()"或者'getall()'方法。
3. getall()方法:提出'Selcetor'中的所有文本,返回的是一个列表。
4. get()放啊:提出'Selcetor'中第一个文本,返回的是一个str字符串。
5. 如果数据解析回来,要传给pipeline处理,那么可以使用yield来返回,或者是提前定义一个空列表,最后return 列表。
6. item:“建议在‘items.py’中定义好模型。
7.pipeline:这是一个专门用来保存数据的,其中有三个方法会被经常用到。
	'open_spider(self, spider)':当爬虫打开时运行
	'process_spider(self, spider)':当爬虫有item传过来的时候被调用。
	'close_spider(self, spider)':当爬虫结束时被调用。
	要激活pipeline:在'settings.py'中打开中间件。

4、保存数据写法优化2

from scrapy.exporters import JsonLinesItemExporter
class QsbkPipeline:
    def __init__(self):
        self.fp = open('duanzi.json', 'wb')
        self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii=False, encoding='utf-8')
    
    # 爬虫开始前调用open_spider
    def open_sipder(self, spider):
        print('这是爬虫开始。。')
    
    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item
    
    # 爬虫结束前调用close_spider
    def close_spider(self, spider):
        self.fp.close()
        print('这是爬虫结束。。')
笔记:
'Jsonitemexporter''jsonLinesitemexporter'
保存json数据的时候,可以使用这两个类,让操作变得简单
1.'Jsonitemexporter':每次把数据添加到内存当中,最后统一写入到磁盘中,好处是:存储的数据是一个满足就送规则的数据,坏处是数据量比较大,比较耗内存。
2'jsonLinesitemexporter':这个是每次调用'export_item'的时候就把这个item存储到硬盘中,坏处是每一个字典是一行,整个问价你不是一个满足json格式的文件,好处是每次处理的数据的时候就直接存储到了硬盘当中,这样不会消耗内存,数据比较安全。

5、糗事百科实现翻页

next_url = response.xpath('//ul[@class="pagination"]/li[last()]/a/@href').get()
     if not next_url:
            return
        else:
            print('https://www.qiushibaike.com/'+next_url)
            yield scrapy.Request('https://www.qiushibaike.com/'+next_url, callback=self.parse)

Request对象

request对象在我们写爬虫时发送一个请求的时候调用,常用参数有:
1. 'url': url地址
2. 'callback': 在下载器下载完成相应数据后执行的回调函数
3. 'method':请求的方法,默认为get
4. 'headers':请求头,一些固定的设置,放在;'setting.py'中制定就可以了,对于非固定的,在发送请求时指定。
5. 'meta': 比较常用用于在不同的请求之间传递数据用。
6. 'encoding':编码,默认为utf-8
7. 'dot_filter':表示不由调度器过滤,在执行多次重复的请求时用的较多。如过之前发送过这个链接请求,调度器默认会拒绝再次发送该请求,所以要设置成Flase
8. 'errback':发成错误时候执行的函数

'Post'请求:Requset子类-> FromRequest来实现 

Reponse对象

1.'meta':从其他请求传过来的meta属性,可以用来保持多个请求之间的数据连接。
2.encoding:返回当前字符串编码和届满的格式
3.'text': 将返回的数据作为Unicode字符串返回。
4.'body':将返回来额数据作为bytes字符串返回。
5.'xpath':xpath选择器。
6.'css':css选择器。

发送Post请求:

'Post'请求:Requset子类-> FromRequest来实现,如果在爬虫一开始时候就发送post请求,那么需要再爬虫类中重写 start_requset(self)方法,并且不再 调用start_requset(self)中的url。

人人网登陆示例:

class RenrenSpider(scrapy.Spider):
    name = 'renren'
    allowed_domains = ['renren.com']
    start_urls = ['http://renren.com']
    
    def start_requests(self):
        url = 'http://www.renren.com/PLogin.do'
        data = {
     'email': '', 'password': ''}
        requset = scrapy.FormRequest(
            url,
            formdata=data,
            callback=self.parse_page
        )
        # 将执行requset
        yield requset
    
    def parse_page(self, response):
        # 访问一下界面【只有登录成功】
        resquset = scrapy.Request(
            url='http://www.renren.com/123456/profile',
            callback=self.parse_profile,
        )
        yield resquset
        
    def parse_profile(self, response):
        with open('dp.html', 'wb', encoding='utf-8') as f:
            f.write(response.text)

import scrapy
from PIL import Image
from urllib import request
class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['douban.com']
    start_urls = ['https://accounts.douban.com/login']
    profile_url = 'https//www.douban.com/people/123456'

    def parse(self, response):
        formdata = {
     
            'source': 'None',
            'redir': 'https://www.douban.com',
            'from_email': '',
            'from_pasword': '',
            'login': '登录',
        }
        captcha_url = response.css('img#captcha_image::attr(src)').get()
        # 如果没有验证码
        if captcha_url:
            captcha = self.regonize_captcha(captcha_url)
            formdata['captcha-solution'] = captcha
            captcha_id = response.xpath('//input[@name="captcha_id"]/@value')
            formdata['captcha_id'] = captcha_id
            yield scrapy.FormRequest(
                url='',
                formdata=formdata,
                callback=self.parase_after_login
                
            )
            
            
    def regonize_captcha(self, image_url):
        # 下载验证码的图片
        request.urlretrieve(image_url, 'capatcha.png')
        image = Image.open('capatcha.png')
        image.show()
        captcha = input('请输入验证码:')
        return captcha
    
    
    def parase_after_login(self, response):
        # 判断是否登录成功
        if response.url == 'https//www.douban.com':
            yield scrapy.Request(
                url=self.profile_url,
                callback=self.parase_profile
            )
            print('登陆成功')
        else:
            print('登录失败')
            
    def parase_profile(self, response):
        print(response.url)
        if response.url == self.profile_url:
            ck = response.xpath('//input[@name="ck"]/@value')
            fromdata ={
     
                'ck': ck,
                'signatures': '则是修改的个人签名'
            }
            print('成功进入该界面')
        else:
            print('没有进入到个人中心')
注意:如果最后一个方法没有给callback,则会自动去执行parse()方法,造成多余回调

下载图片

为什么要选择使用scrapy内置的下载文件的方法:

1.避免重新下线最近已经下载过的数据。
2.可以方便的指定文件存储的路径。
3.可以将下裁的图片转换成通用的格式。比如png或pg。
4.可以方便的生成睿备图。
5.可以方便的检测图片的宽和高,确保他们满足最小限制。
6.异步下载,效率非常高。

下载文件的 Files Pipeline :

当使用Files Pipeline下戏文件的时候,按照以下步强来完成:
1.定义好一个Iten ,然后在这个iten中定义两个属性,分别为
File url以及filcs 。file_urls是用来存储需要下裁的文件的
ur链接,需要给一个列表。
2.当文件下或完成后,会把文件下载的相关信息存储到iten的 files 属性中。比如下或路径、下觌的uri和文件的校猃
3.在配用文件 settings.py 中配嚣FILEs_STORE ,这个配用是用来设用文件下赖下来的路径。
4.启动pipeline:ITEN_PIPELINES 中设置scrapy.pipelines.files. FilesPipcline:1 .

下载图片的Images Pipeline :

当使用Images Pipeline下锐文件的时候,按照以下步骏来完成:
1.定义好一个 Item ,然后在这个iten 中定义两个属性,分别为 inago _un1s 以及 imsges . inage_ur1s 是用来存储需要下赖的图片的url链接,需要给一个列表。
2.当文件下戟完成后,会把文件下载的相关信息存储到item的imsges属性中。比扣下载路径、下觌的url和图片的核金码等。
3.在配置文件 settings.py中配置1HAGEs_STORE ,这个配置是用来设置图片下载下来的路径。
4.启动pipeline :ITEN_PIPELINES 中设置scrapy.pioelines.images.ImagesPipeline

下载器中间件

下载器中间件我们可以设置代理,更换请求头来达成反反爬虫的目的。
要写下载器中间件,可以在下载其中实现两个方法,一个是process_request(self,requset,spider),这个方法会在请求发送之前执行。还有一个是'process_response(selfm response, spider)'在数据下载到引擎之前执行。

随机请求头

/middlerwares.py下
class UserAgentDOwnloadMiddleware(object):
	user_agent = [
    "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 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11",
    "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
    "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; Maxthon 2.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
    "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
    "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
    "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
    "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
    "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
    "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
    "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
    "UCWEB7.0.2.37/28/999",
    "NOKIA5700/ UCWEB7.0.2.37/28/999",
    "Openwave/ UCWEB7.0.2.37/28/999",
    "Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999",
    # iPhone 6"Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25",
 

	def process_request(self, requeset, spider):
	user_agent = random.choice(user_agents)
	requset.heasers['User_Agent'] = user-agent

ip代理池中间件

1.通过连接提取ip

/middlewares.py
class IPProxyDownloadMiddleware(object):
	def ___init(self):
		proxys = ['127.0.0.1:800']
	def process_request(self, request, spider):
	proxy = random.choice(self.proxys )
	request.meta['proxy'] = proxy

2. 快代理之独享代理

/middlewares.py
class IPProxyDownloadMiddleware(object):
	def process_request(self, request, spider):
	proxy = '121.1999.6.124:16816'
	user_password = 'username:password'
	request.meta['proxy'] = proxy
	b64_user_pwd = base64.b64encode(user_password.encode('urf-8'))
	request.headers['Proxy-Authorization'] = 'Basic '+ b64_user_pwd 

你可能感兴趣的:(python笔记,python,爬虫)