爬虫技术:scrapy 知识点一

---恢复内容开始---

1.scrapy框架

  

每一步的解释:

step1:引擎从爬虫器获取要爬行的初始请求。

step2:引擎在调度程序中调度请求,引擎把这个初始请求传递给调度器,并向调度器索要下一个请求。

step3:调度程序将下一个请求返回给引擎。

step4:引擎通过下载器中间件将请求发送给下载器。

step5:一旦页面下载完成,下载器就会生成一个响应(带有该页面)并将通过下载器中间件响应发送到引擎。

step6:引擎接收来自下载器的响应,并通过Spider中间件将其发送给Spider进行处理。

step7:爬行器处理响应,并通过爬行器中间件将抓取的数据和新请求(要跟踪的)返回给引擎

step8:引擎将处理过的数据发送到数据管道,然后将处理过的请求发送到调度程序,并请求可能的下一个要爬行的请求。

step9:流程重复(从步骤1开始),直到调度程序不再发出请求。

 

每一个元件的作用:

引擎 Engine:负责控制系统所有组件之间的数据流,并在某些操作发生时触发事件

调度器:调度器接收来自引擎的请求,并对它们进行排队,以便稍后在引擎请求它们时将请求对象提供给引擎。

下载器:下载器负责获取web页面并将响应内容提供给引擎,而引擎又将响应内容提供给爬虫器。

爬虫器:spider是由Scrapy用户编写的自定义类,用于解析响应并从响应或后续请求中提取数据(也称为抓取数据)。

管道:项目管道负责处理爬虫提取(或处理)后的数据。典型的任务包括清理数据、验证和持久性(比如在数据库中存储)。

下载器中间件:Downloader中间件是位于引擎和Downloader之间的特定钩子,当请求从引擎传递到Downloader以及响应从Downloader传递到引擎时,处理引擎和下载器中间的请求和响应,并进行传递

爬虫中间件:Spider中间件是位于引擎和Spider之间的特定钩子,能够处理Spider输入(响应)和输出(数据请求)

内容翻译于https://doc.scrapy.org/en/master/topics/architecture.html

scrapy框架:Scrapy是用Twisted编写的,Twisted是一种流行的Python事件驱动的网络框架因此,它使用非阻塞(即异步)代码实现并发

 

Frequently Asked Questions:框架的常见问题

1.Scrapy可以使用HTTP代理吗?

是的。通过HTTP代理下载器中间件提供了对HTTP代理的支持(因为Scrapy 0.8)。具体见:HttpProxyMiddleware。

 

使用方式一:在中间件,middlewares.py中添加如下代码。

class ProxyMiddleware(object):
def process_request(self,request,spider):
if request.url.startswith("http://"):
request.meta[
'proxy']="http://"+'127.0.0.0:8000' # http代理
elif request.url.startswith("https://"):
request.meta[
'proxy']="https://"+'127.0.0.0:8000' # https代理 然后在setting.py中的middleware中设置 # Enable or disable downloader middlewares # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = { 'biquge.middlewares.ProxyMiddleware': 100, }

 

使用方式二:在scarpy的爬虫代码中进行编写,重写start_request()函数,通过meta字典传递代理。

import scrapy

class ProxySpider(scrapy.Spider):

    name = 'proxy'
    allowed_domains = ["httpbin.org"]

    def start_requests(self):

        url = 'http://httpbin.org/get'
        proxy = '127.0.0.0:8000'

        proxies = ""

        if url.startswith("http://"):

            proxies = "http://"+str(proxy)

        elif url.startswith("https://"):

            proxies = "https://"+str(proxy)

        #注意这里面的meta={'proxy':proxies},一定要是proxy进行携带,其它的不行,后面的proxies一定 要是字符串,其它任何形式都不行

        yield scrapy.Request(url, callback=self.parse,meta={'proxy':proxies})

    def parse(self,response):
        print(response.text)

CrawlSpider类 

   rules:

    它是一个(或多个)规则对象的列表。每个规则都定义了爬行站点的特定行为。规则对象描述如下。如果多个规则匹配相同的链接,则根据在此属性中定义规则的顺序使用第一个规则有自动去重url的功能

   Rule(link_extractorcallback=Nonecb_kwargs=Nonefollow=Noneprocess_links=Noneprocess_request=None)

 百度百科案例:深度爬取

# -*- coding: utf-8 -*-
import lxml.etree

import scrapy
from scrapy.spiders import CrawlSpider,Rule   #提取超链接的规则
from scrapy.linkextractors import LinkExtractor # 提取超链接
from bidubaike.items import BidubaikeItem



class BaidubaikeSpider(CrawlSpider):  # scrapy.Spider
    name = 'baidubaike'
    # 规则匹配的url样式,https://baike.baidu.com/item/%E5%A5%BD%E5%A5%BD%E8%AF%B4%E8%AF%9D/20361348?secondId=165077&mediaId=mda-hcssahwn1h3mk6zz'
    # allowed_domains = ['https://baike.baidu.com/']  # 这里需要关闭这个功能
    # 或者设置为下面形式
    allowed_domins = ['https://baike.baidu.com/item/']
    start_urls = ['https://baike.baidu.com/item/Python/407313']

    # 页面提取超链接  TODO 规则定义为每一页的url,也可以实现翻页
    pagelinks = LinkExtractor(allow=(r"/item/.*"))  # 提取规则
    # follow表示是否一致循环下去
    rules = [Rule(pagelinks,callback="parse_item",follow=True)]  # 返回链接的urllist


    # 这里不能用原生的def parse()方法,需要换一个名称,要不不能实现
    def parse_item(self, response):
        html = response.body.decode("utf-8")
        item = BidubaikeItem()
        e = lxml.etree.HTML(html)
        if html != None:
            title1 = e.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']//h1/text()")
            if len(title1) == 0:
                part_a = ""
            else:
                part_a = title1[0]
            title2 = e.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']//h2/text()")
            if len(title2) == 0:
                part_b = ""
            else:
                part_b = title2[0]
            title = part_a + part_b
            title += "\r\n"
            item["title"] = title
            item["url"] = response.url
            yield item

        else:
            item["title"] = None
            item["url"] = None
            yield item

 

配置随机代理的方式:

方式一:

setting.py中设置:

PROXIES = [
        "http://120.84.102.21:9999",
        "http://114.239.150.233:9999",
        "http://112.87.71.174:9999"

]
在middleware.py中创建一个类

class ProxyMiddleWare(object):

    def __init__(self,ip):
        self.ip = ip  # 列表

    @classmethod
    def from_crawler(cls, crawler):
        # 从setting.py中得到PORXIES列表
        return cls(ip=crawler.setting.get("PORXIES")) # 列表

    def process_request(self,request,spider):
        ip = random.choice(self.ip) # 列表中随机选值
        request.meta["proxy"] = ip  # 给请求对象加上代理参数
setting.py中开启DOWNLOADER_MIDDLEWARES 并将middlewares.py中创建的类添加进去。

DOWNLOADER_MIDDLEWARES = {
   'Proxy.middlewares.ProxyDownloaderMiddleware': 543,
    'Proxy.middlewares.ProxyMiddleWare':543,
}

 

 scrapy登录操作:无验证类

# -*- coding: utf-8 -*-
import scrapy

class RenrenloginSpider(scrapy.Spider):
    name = 'renrenlogin'
    allowed_domains = ['www.renren.com']
    start_urls = ['http://www.renren.com/SysHome.do'] # 人人登录界面网址

    def parse(self, response):
        """表单登录,发送用户名和验证码"""
        yield scrapy.FormRequest.from_response(response,
                                               formdata={"email":"xxx","password":"xxx"}, # 这里scarpy会自动模拟js对email和passowrd进行加密
                                               callback = self.parse_person_homepage)

    def parse_person_homepage(self, response):
        homepage_url = "http://www.renren.com/xxx/profile"
        yield scrapy.Request(url=homepage_url,callback=self.parse_user_info)

    def parse_user_info(self,response):
        html = response.body
        with open("renren.html","w") as f:
            f.write(html.decode("gbk","ignore"))

scrapy登录操作:无验证类 --- 利用cookie跳转到其他页面

# -*- coding: utf-8 -*-
import scrapy


class RenrenloginSpider(scrapy.Spider):
    name = 'csdnlogin.py'
    allowed_domains = ['www.csdn.net']
    start_urls = ['https://passport.csdn.net/guide']
   # 手动登录后获取到cookies,利用fidder抓取到cookies包,进行请求。 cookies = { "uuid_tt_dd": "xxx", "dc_session_id": "xxx", "smidV2": "xxx", "UN": "xxx", "Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac": "xxx", "Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac": "xxx", "aliyun_webUmidToken": "xxx", "MSG-SESSION": "xxx", "SESSION": "xxx", "dc_tos": "xxx", "UserName": "xxx", "UserInfo": "xxx", "UserToken": "xxx", "UserNick": "xxx", "AU": "xxx", "BT": "xxx", "p_uid": "xxx", "Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac": "xxx" } def start_requests(self): for url in self.start_urls: yield scrapy.FormRequest(url=url,cookies=self.cookies,callback=self.parse_newpage) def parse_newpage(self,response): with open("csdn.html","wb") as f: f.write(response.body)

 报错:Connection to the other side was lost in a non-clean fashion.  爬取问政的时候

 构造url_list进行爬取---阳光问政

import re
import lxml.etree
import scrapy
from sun.items import SunItem

class SuninfoSpider(scrapy.Spider):
    name = 'suninfo'
    allowed_domains = ['wz.sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=0']

    def parse(self, response):
        html_str = response.body.decode("gbk",errors="ignore")
        e = lxml.etree.HTML(html_str)
        count_str = e.xpath("//div[@class='pagination']/text()")[-1]
        # 获取帖子数量
        count = re.findall("(\d+)", count_str)[0]
        page_count = int(count) // 30
        url_list = list()
        url = "http://wz.sun0769.com/index.php/question/report?page={}"
        for i in range(0, page_count + 1):
            url_list.append(url.format(i * 30))
        # 测试10页的数据
        for url in url_list[:10]:
            yield scrapy.Request(url=url,callback=self.parse_page_info)

    def parse_page_info(self,response):
        html_str = response.body.decode("gbk",errors="ignore")
        e = lxml.etree.HTML(html_str)
        item = SunItem()
        tr_list = e.xpath("//div[@class='newsHead clearfix']//table[2]//tr")
        for tr in tr_list:
            item["id"] = tr.xpath(".//td[1]/text()")[0]
            item["title"] = tr.xpath(".//td[3]//a[1]/text()")[0]
            person = tr.xpath(".//td[5]/text()")
            if len(person) == 0:
                person = "MISS"
                item["name"] = person
            else:
                person = tr.xpath(".//td[5]/text()")[0]
                item["name"] = person
            item["time"] = tr.xpath(".//td[6]/text()")[0]
            yield item

自动抓取页面链接爬取---阳光问政

# -*- coding: utf-8 -*-
import re
import lxml.etree
import scrapy
from sun.items import SunItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor


class SuninfoSpider(CrawlSpider):
    name = 'suninfo'
    # allowed_domains = ['wz.sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=0']
    # http://wz.sun0769.com/index.php/question/report?page=30"
    # 提取规则的正则是由Linkextractor进行设置的
    pagelink = LinkExtractor(allow=(r"page=.*"))
    rules = [Rule(pagelink, callback="parse_item", follow=True)]

    def parse_item(self, response):
        html_str = response.body.decode("gbk", errors="ignore")
        e = lxml.etree.HTML(html_str)
        item = SunItem()
        tr_list = e.xpath("//div[@class='newsHead clearfix']//table[2]//tr")
        for tr in tr_list:
            item["id"] = tr.xpath(".//td[1]/text()")[0]
            item["title"] = tr.xpath(".//td[3]//a[1]/text()")[0]
            person = tr.xpath(".//td[5]/text()")
            if len(person) == 0:
                person = "MISS"
                item["name"] = person
            else:
                person = tr.xpath(".//td[5]/text()")[0]
                item["name"] = person
            item["time"] = tr.xpath(".//td[6]/text()")[0]
            yield item

 

scary框架的去重原理:

  第一步:框架工具包中的scrapy/utils/request.py     

      request_fingerprint函数---对请求对象进行签名--sha1

       怎么判断请求对象是同一个呢,签名时候,对请求对象的 method,url,body(包含请求头)进行加密

       请求体:request.body样子是什么呢?  # TODO

      sha1加密:

from hashlib import sha1
fp = sha1()

str1 = "a"
str2 = "b"
str3 = "c"

fp.update(str1.encode())
fp.update(str2.encode())
fp.update(str2.encode())

# 理解为:对str1 + str2 + str3 = "abc" 进行加密,因为sha1对任何长度的二进制数据加密后都得到40位的16进制字符串。 ret
= fp.hexdigest() print(ret) c64d3fcde20c5cd03142171e5ac47a87aa3c8ace # 生成一个40位长度的16进制的字符串。

  第二步:去重工具:scrapy/dupefilters.py  

    集合(防止指纹(长度为40的字符串))  set(指纹1,指纹2,指纹3,。。。。,)

    request_seen---看见函数,对指纹进行处理,

      指纹在集合就直接返回,不进行下一步,return True

      指纹不在集合,就加入集合,再进行下一步。

  第三步:scrapy/core/scheduler.py/enqueue_request   调度器

      enqueue_request 函数中:request对象的 dont_fliter=false且当前request对象的签名在集合中。那么就将当前的请求对象放入请求队列中去。

  具体代码分析:https://blog.csdn.net/Mr__lqy/article/details/85859361

 

输出log日志

 

settings中

LOG_FILE = "0769.log"
LOG_LEVEL = "DEBUG"

控制台不做任何输出,结果都写在名为0769的日志文件中。

 

scrapy抓取json数据

  图片下载保存方法一:urllib.request

 

 

import urllib.request

class DouyumeinvPipeline(object):
    def process_item(self, item, spider):
        url = item["imgurl"]
        name = item["id"]
        urllib.request.urlretrieve(url,"pic/{}.jpg".format(name)) # 直接使用urllib.request中的urlretrieve函数,直接将请求的资源保存指定路径
        return item

 

  图片下载保存方法二:Imagepipeline

# setting.py中设置:

ITEM_PIPELINES = {
   'douyuimage.pipelines.ImagePipeLine': 1,
}
# 实际上图片是全部默认保存在full文件夹中,full文件夹则保存在IMAGE_STORE这个路径下。 IMAGES_STORE
= r'C:\Users\Administrator\Desktop\img' IMAGES_EXPIRES = 90 # pipelines.py中设置: class ImagePipeLine(ImagesPipeline): def get_media_requests(self, item, info):
     # 每个item都会经过这个函数,然后这个函数在发起一个请求对象,将结果传给 item_completed函数 url
= item["img_url"] yield scrapy.Request(url) def item_completed(self, results, item, info): # results = [(True,{"path":"full/xxxxxx.jpg"})] image_path = [x['path'] for ok, x in results if ok] # 仅仅是图片路径是:full/xxxx.jpg if not image_path: raise DouyuimageItem("Item contains no images") item['image_path'] = image_path return item # 在items中设置: class DouyuimageItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() id = scrapy.Field() name = scrapy.Field() img_url = scrapy.Field() image_path = scrapy.Field() pass # spider.py中设置: class ImgdownSpider(scrapy.Spider): name = 'imgdown' allowed_domains = ['www.douyu.com'] current_page = 1 start_urls = ['https://www.douyu.com/gapi/rknc/directory/yzRec/{}'.format(current_page)] def parse(self, response): item = DouyuimageItem() data = json.loads(response.body.decode())["data"] info_dict_list = data["rl"] for info_dict in info_dict_list: item["id"] = info_dict["rid"] item["name"] = info_dict["nn"] item["img_url"] = info_dict["rs16"] yield item # 运行的结果 {'id': 6837192, 'image_path': ['full/e63847f2205b92e0a6c46c17d68e37f708948337.jpg'], 'img_url': 'https://rpic.douyucdn.cn/asrpic/190916/6837192_6066111_26880_2_1546.jpg', 'name': '十三金丶'}

 

 

 scrapy翻页抓取数据

  翻页抓取数据方式一:页码递增法

 

import requests
from bs4 import BeautifulSoup

url = "https://blog.csdn.net/itcastcpp/article/list/1?"

html_content = requests.get(url).content

soup = BeautifulSoup(html_content,"html5lib")  # 将网页的字节数据解析为html5的类型

div_list = soup.find_all("div",class_="article-item-box csdn-tracking-statistics") # 按照class的属性进行寻找。

for div in div_list:
    title = (div.find_all("h4")[0]).find_all("a")[0]
    # 获取h4下的a标签的文本值
    print(title.get_text())

# 结果:

        原        兄弟连区块链  Go 学习大纲-取得大纲试看视频联系微信yinchengak48      

        原        尹成学院golang学习快速笔记(2)表达式      

        原        尹成学院golang学习快速笔记(1)类型      

        原        区块链交易所基础开发(1)通过接口查询区块链各个币种的提币情况-ada      

        原        Golang精编100题-搞定golang面试      

 

 

 

  

---恢复内容结束---

---恢复内容开始---

1.scrapy框架

  

每一步的解释:

step1:引擎从爬虫器获取要爬行的初始请求。

step2:引擎在调度程序中调度请求,引擎把这个初始请求传递给调度器,并向调度器索要下一个请求。

step3:调度程序将下一个请求返回给引擎。

step4:引擎通过下载器中间件将请求发送给下载器。

step5:一旦页面下载完成,下载器就会生成一个响应(带有该页面)并将通过下载器中间件响应发送到引擎。

step6:引擎接收来自下载器的响应,并通过Spider中间件将其发送给Spider进行处理。

step7:爬行器处理响应,并通过爬行器中间件将抓取的数据和新请求(要跟踪的)返回给引擎

step8:引擎将处理过的数据发送到数据管道,然后将处理过的请求发送到调度程序,并请求可能的下一个要爬行的请求。

step9:流程重复(从步骤1开始),直到调度程序不再发出请求。

 

每一个元件的作用:

引擎 Engine:负责控制系统所有组件之间的数据流,并在某些操作发生时触发事件

调度器:调度器接收来自引擎的请求,并对它们进行排队,以便稍后在引擎请求它们时将请求对象提供给引擎。

下载器:下载器负责获取web页面并将响应内容提供给引擎,而引擎又将响应内容提供给爬虫器。

爬虫器:spider是由Scrapy用户编写的自定义类,用于解析响应并从响应或后续请求中提取数据(也称为抓取数据)。

管道:项目管道负责处理爬虫提取(或处理)后的数据。典型的任务包括清理数据、验证和持久性(比如在数据库中存储)。

下载器中间件:Downloader中间件是位于引擎和Downloader之间的特定钩子,当请求从引擎传递到Downloader以及响应从Downloader传递到引擎时,处理引擎和下载器中间的请求和响应,并进行传递

爬虫中间件:Spider中间件是位于引擎和Spider之间的特定钩子,能够处理Spider输入(响应)和输出(数据请求)

内容翻译于https://doc.scrapy.org/en/master/topics/architecture.html

scrapy框架:Scrapy是用Twisted编写的,Twisted是一种流行的Python事件驱动的网络框架因此,它使用非阻塞(即异步)代码实现并发

 

Frequently Asked Questions:框架的常见问题

1.Scrapy可以使用HTTP代理吗?

是的。通过HTTP代理下载器中间件提供了对HTTP代理的支持(因为Scrapy 0.8)。具体见:HttpProxyMiddleware。

 

使用方式一:在中间件,middlewares.py中添加如下代码。

class ProxyMiddleware(object):
def process_request(self,request,spider):
if request.url.startswith("http://"):
request.meta[
'proxy']="http://"+'127.0.0.0:8000' # http代理
elif request.url.startswith("https://"):
request.meta[
'proxy']="https://"+'127.0.0.0:8000' # https代理 然后在setting.py中的middleware中设置 # Enable or disable downloader middlewares # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = { 'biquge.middlewares.ProxyMiddleware': 100, }

 

使用方式二:在scarpy的爬虫代码中进行编写,重写start_request()函数,通过meta字典传递代理。

import scrapy

class ProxySpider(scrapy.Spider):

    name = 'proxy'
    allowed_domains = ["httpbin.org"]

    def start_requests(self):

        url = 'http://httpbin.org/get'
        proxy = '127.0.0.0:8000'

        proxies = ""

        if url.startswith("http://"):

            proxies = "http://"+str(proxy)

        elif url.startswith("https://"):

            proxies = "https://"+str(proxy)

        #注意这里面的meta={'proxy':proxies},一定要是proxy进行携带,其它的不行,后面的proxies一定 要是字符串,其它任何形式都不行

        yield scrapy.Request(url, callback=self.parse,meta={'proxy':proxies})

    def parse(self,response):
        print(response.text)

CrawlSpider类 

   rules:

    它是一个(或多个)规则对象的列表。每个规则都定义了爬行站点的特定行为。规则对象描述如下。如果多个规则匹配相同的链接,则根据在此属性中定义规则的顺序使用第一个规则有自动去重url的功能

   Rule(link_extractorcallback=Nonecb_kwargs=Nonefollow=Noneprocess_links=Noneprocess_request=None)

 百度百科案例:深度爬取

# -*- coding: utf-8 -*-
import lxml.etree

import scrapy
from scrapy.spiders import CrawlSpider,Rule   #提取超链接的规则
from scrapy.linkextractors import LinkExtractor # 提取超链接
from bidubaike.items import BidubaikeItem



class BaidubaikeSpider(CrawlSpider):  # scrapy.Spider
    name = 'baidubaike'
    # 规则匹配的url样式,https://baike.baidu.com/item/%E5%A5%BD%E5%A5%BD%E8%AF%B4%E8%AF%9D/20361348?secondId=165077&mediaId=mda-hcssahwn1h3mk6zz'
    # allowed_domains = ['https://baike.baidu.com/']  # 这里需要关闭这个功能
    # 或者设置为下面形式
    allowed_domins = ['https://baike.baidu.com/item/']
    start_urls = ['https://baike.baidu.com/item/Python/407313']

    # 页面提取超链接  TODO 规则定义为每一页的url,也可以实现翻页
    pagelinks = LinkExtractor(allow=(r"/item/.*"))  # 提取规则
    # follow表示是否一致循环下去
    rules = [Rule(pagelinks,callback="parse_item",follow=True)]  # 返回链接的urllist


    # 这里不能用原生的def parse()方法,需要换一个名称,要不不能实现
    def parse_item(self, response):
        html = response.body.decode("utf-8")
        item = BidubaikeItem()
        e = lxml.etree.HTML(html)
        if html != None:
            title1 = e.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']//h1/text()")
            if len(title1) == 0:
                part_a = ""
            else:
                part_a = title1[0]
            title2 = e.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']//h2/text()")
            if len(title2) == 0:
                part_b = ""
            else:
                part_b = title2[0]
            title = part_a + part_b
            title += "\r\n"
            item["title"] = title
            item["url"] = response.url
            yield item

        else:
            item["title"] = None
            item["url"] = None
            yield item

 

配置随机代理的方式:

方式一:

setting.py中设置:

PROXIES = [
        "http://120.84.102.21:9999",
        "http://114.239.150.233:9999",
        "http://112.87.71.174:9999"

]
在middleware.py中创建一个类

class ProxyMiddleWare(object):

    def __init__(self,ip):
        self.ip = ip  # 列表

    @classmethod
    def from_crawler(cls, crawler):
        # 从setting.py中得到PORXIES列表
        return cls(ip=crawler.setting.get("PORXIES")) # 列表

    def process_request(self,request,spider):
        ip = random.choice(self.ip) # 列表中随机选值
        request.meta["proxy"] = ip  # 给请求对象加上代理参数
setting.py中开启DOWNLOADER_MIDDLEWARES 并将middlewares.py中创建的类添加进去。

DOWNLOADER_MIDDLEWARES = {
   'Proxy.middlewares.ProxyDownloaderMiddleware': 543,
    'Proxy.middlewares.ProxyMiddleWare':543,
}

 

 scrapy登录操作:无验证类

# -*- coding: utf-8 -*-
import scrapy

class RenrenloginSpider(scrapy.Spider):
    name = 'renrenlogin'
    allowed_domains = ['www.renren.com']
    start_urls = ['http://www.renren.com/SysHome.do'] # 人人登录界面网址

    def parse(self, response):
        """表单登录,发送用户名和验证码"""
        yield scrapy.FormRequest.from_response(response,
                                               formdata={"email":"xxx","password":"xxx"}, # 这里scarpy会自动模拟js对email和passowrd进行加密
                                               callback = self.parse_person_homepage)

    def parse_person_homepage(self, response):
        homepage_url = "http://www.renren.com/xxx/profile"
        yield scrapy.Request(url=homepage_url,callback=self.parse_user_info)

    def parse_user_info(self,response):
        html = response.body
        with open("renren.html","w") as f:
            f.write(html.decode("gbk","ignore"))

scrapy登录操作:无验证类 --- 利用cookie跳转到其他页面

# -*- coding: utf-8 -*-
import scrapy


class RenrenloginSpider(scrapy.Spider):
    name = 'csdnlogin.py'
    allowed_domains = ['www.csdn.net']
    start_urls = ['https://passport.csdn.net/guide']
   # 手动登录后获取到cookies,利用fidder抓取到cookies包,进行请求。 cookies = { "uuid_tt_dd": "xxx", "dc_session_id": "xxx", "smidV2": "xxx", "UN": "xxx", "Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac": "xxx", "Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac": "xxx", "aliyun_webUmidToken": "xxx", "MSG-SESSION": "xxx", "SESSION": "xxx", "dc_tos": "xxx", "UserName": "xxx", "UserInfo": "xxx", "UserToken": "xxx", "UserNick": "xxx", "AU": "xxx", "BT": "xxx", "p_uid": "xxx", "Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac": "xxx" } def start_requests(self): for url in self.start_urls: yield scrapy.FormRequest(url=url,cookies=self.cookies,callback=self.parse_newpage) def parse_newpage(self,response): with open("csdn.html","wb") as f: f.write(response.body)

 报错:Connection to the other side was lost in a non-clean fashion.  爬取问政的时候

 构造url_list进行爬取---阳光问政

import re
import lxml.etree
import scrapy
from sun.items import SunItem

class SuninfoSpider(scrapy.Spider):
    name = 'suninfo'
    allowed_domains = ['wz.sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=0']

    def parse(self, response):
        html_str = response.body.decode("gbk",errors="ignore")
        e = lxml.etree.HTML(html_str)
        count_str = e.xpath("//div[@class='pagination']/text()")[-1]
        # 获取帖子数量
        count = re.findall("(\d+)", count_str)[0]
        page_count = int(count) // 30
        url_list = list()
        url = "http://wz.sun0769.com/index.php/question/report?page={}"
        for i in range(0, page_count + 1):
            url_list.append(url.format(i * 30))
        # 测试10页的数据
        for url in url_list[:10]:
            yield scrapy.Request(url=url,callback=self.parse_page_info)

    def parse_page_info(self,response):
        html_str = response.body.decode("gbk",errors="ignore")
        e = lxml.etree.HTML(html_str)
        item = SunItem()
        tr_list = e.xpath("//div[@class='newsHead clearfix']//table[2]//tr")
        for tr in tr_list:
            item["id"] = tr.xpath(".//td[1]/text()")[0]
            item["title"] = tr.xpath(".//td[3]//a[1]/text()")[0]
            person = tr.xpath(".//td[5]/text()")
            if len(person) == 0:
                person = "MISS"
                item["name"] = person
            else:
                person = tr.xpath(".//td[5]/text()")[0]
                item["name"] = person
            item["time"] = tr.xpath(".//td[6]/text()")[0]
            yield item

自动抓取页面链接爬取---阳光问政

# -*- coding: utf-8 -*-
import re
import lxml.etree
import scrapy
from sun.items import SunItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor


class SuninfoSpider(CrawlSpider):
    name = 'suninfo'
    # allowed_domains = ['wz.sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=0']
    # http://wz.sun0769.com/index.php/question/report?page=30"
    # 提取规则的正则是由Linkextractor进行设置的
    pagelink = LinkExtractor(allow=(r"page=.*"))
    rules = [Rule(pagelink, callback="parse_item", follow=True)]

    def parse_item(self, response):
        html_str = response.body.decode("gbk", errors="ignore")
        e = lxml.etree.HTML(html_str)
        item = SunItem()
        tr_list = e.xpath("//div[@class='newsHead clearfix']//table[2]//tr")
        for tr in tr_list:
            item["id"] = tr.xpath(".//td[1]/text()")[0]
            item["title"] = tr.xpath(".//td[3]//a[1]/text()")[0]
            person = tr.xpath(".//td[5]/text()")
            if len(person) == 0:
                person = "MISS"
                item["name"] = person
            else:
                person = tr.xpath(".//td[5]/text()")[0]
                item["name"] = person
            item["time"] = tr.xpath(".//td[6]/text()")[0]
            yield item

 

scary框架的去重原理:

  第一步:框架工具包中的scrapy/utils/request.py     

      request_fingerprint函数---对请求对象进行签名--sha1

       怎么判断请求对象是同一个呢,签名时候,对请求对象的 method,url,body(包含请求头)进行加密

       请求体:request.body样子是什么呢?  # TODO

      sha1加密:

from hashlib import sha1
fp = sha1()

str1 = "a"
str2 = "b"
str3 = "c"

fp.update(str1.encode())
fp.update(str2.encode())
fp.update(str2.encode())

# 理解为:对str1 + str2 + str3 = "abc" 进行加密,因为sha1对任何长度的二进制数据加密后都得到40位的16进制字符串。 ret
= fp.hexdigest() print(ret) c64d3fcde20c5cd03142171e5ac47a87aa3c8ace # 生成一个40位长度的16进制的字符串。

  第二步:去重工具:scrapy/dupefilters.py  

    集合(防止指纹(长度为40的字符串))  set(指纹1,指纹2,指纹3,。。。。,)

    request_seen---看见函数,对指纹进行处理,

      指纹在集合就直接返回,不进行下一步,return True

      指纹不在集合,就加入集合,再进行下一步。

  第三步:scrapy/core/scheduler.py/enqueue_request   调度器

      enqueue_request 函数中:request对象的 dont_fliter=false且当前request对象的签名在集合中。那么就将当前的请求对象放入请求队列中去。

  具体代码分析:https://blog.csdn.net/Mr__lqy/article/details/85859361

 

输出log日志

 

settings中

LOG_FILE = "0769.log"
LOG_LEVEL = "DEBUG"

控制台不做任何输出,结果都写在名为0769的日志文件中。

 

scrapy抓取json数据

  图片下载保存方法一:urllib.request

 

 

import urllib.request

class DouyumeinvPipeline(object):
    def process_item(self, item, spider):
        url = item["imgurl"]
        name = item["id"]
        urllib.request.urlretrieve(url,"pic/{}.jpg".format(name)) # 直接使用urllib.request中的urlretrieve函数,直接将请求的资源保存指定路径
        return item

 

  图片下载保存方法二:Imagepipeline

# setting.py中设置:

ITEM_PIPELINES = {
   'douyuimage.pipelines.ImagePipeLine': 1,
}
# 实际上图片是全部默认保存在full文件夹中,full文件夹则保存在IMAGE_STORE这个路径下。 IMAGES_STORE
= r'C:\Users\Administrator\Desktop\img' IMAGES_EXPIRES = 90 # pipelines.py中设置: class ImagePipeLine(ImagesPipeline): def get_media_requests(self, item, info):
     # 每个item都会经过这个函数,然后这个函数在发起一个请求对象,将结果传给 item_completed函数 url
= item["img_url"] yield scrapy.Request(url) def item_completed(self, results, item, info): # results = [(True,{"path":"full/xxxxxx.jpg"})] image_path = [x['path'] for ok, x in results if ok] # 仅仅是图片路径是:full/xxxx.jpg if not image_path: raise DouyuimageItem("Item contains no images") item['image_path'] = image_path return item # 在items中设置: class DouyuimageItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() id = scrapy.Field() name = scrapy.Field() img_url = scrapy.Field() image_path = scrapy.Field() pass # spider.py中设置: class ImgdownSpider(scrapy.Spider): name = 'imgdown' allowed_domains = ['www.douyu.com'] current_page = 1 start_urls = ['https://www.douyu.com/gapi/rknc/directory/yzRec/{}'.format(current_page)] def parse(self, response): item = DouyuimageItem() data = json.loads(response.body.decode())["data"] info_dict_list = data["rl"] for info_dict in info_dict_list: item["id"] = info_dict["rid"] item["name"] = info_dict["nn"] item["img_url"] = info_dict["rs16"] yield item # 运行的结果 {'id': 6837192, 'image_path': ['full/e63847f2205b92e0a6c46c17d68e37f708948337.jpg'], 'img_url': 'https://rpic.douyucdn.cn/asrpic/190916/6837192_6066111_26880_2_1546.jpg', 'name': '十三金丶'}

 

 

 scrapy翻页抓取数据

  翻页抓取数据方式一:页码递增法

 

import requests
from bs4 import BeautifulSoup

url = "https://blog.csdn.net/itcastcpp/article/list/1?"

html_content = requests.get(url).content

soup = BeautifulSoup(html_content,"html5lib")  # 将网页的字节数据解析为html5的类型

div_list = soup.find_all("div",class_="article-item-box csdn-tracking-statistics") # 按照class的属性进行寻找。

for div in div_list:
    title = (div.find_all("h4")[0]).find_all("a")[0]
    # 获取h4下的a标签的文本值
    print(title.get_text())

# 结果:

        原        兄弟连区块链  Go 学习大纲-取得大纲试看视频联系微信yinchengak48      

        原        尹成学院golang学习快速笔记(2)表达式      

        原        尹成学院golang学习快速笔记(1)类型      

        原        区块链交易所基础开发(1)通过接口查询区块链各个币种的提币情况-ada      

        原        Golang精编100题-搞定golang面试      

 scrapy中cookie的设置方法

  方式一:setting中设置即可

第一步,打开setting中的DEFAULT_REQUEST_HEADER的注释
在里面添加Cookie:"xxxx"的键值对,从浏览器中复制即可
# 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',
 "Cookie": "xxx"}

第二步,打来# COOKIES_ENABLED = False的注释,不授权使用cookie

第三步,开启爬虫

 

   方式二:在爬虫类中重写start_requests方法

# 第一步,在spider.py中重写start_requests方法,增加cookie

    def start_requests(self):
        url = self.start_urls[0]
        cookies = {
                        "uuid_tt_dd":"xx",
                        "dc_session_id":"xx,
                        "smidV2":"xx",
                        "UN":"xx",
                        "Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac":"xx",             
                        "acw_tc":"xx", 
                        "Hm_ct_e5ef47b9f471504959267fd614d579cd":"xx", 
                        "__yadk_uid":"xx",
                        "firstDie":"xx",
                        "UserName":"xx",
                        "UserInfo":"xx",
                        "UserToken":"xx",
                        "UserNick":"xx",
                        "BT":"xx",
                        "p_uid":"xx",
                        "Hm_lvt_e5ef47b9f471504959267fd614d579cd":"xx", 
                        "Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac":"xx",
                        "acw_sc__v3":"xx",
                        "acw_sc__v2":"xx",
                        "dc_tos":"xx",
                        "Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac":"xx"}

        yield scrapy.Request(url,cookies=cookies,callback=self.parse)   

第二步:保持# Disable cookies (enabled by default)的注释状态,不要打开
# COOKIES_ENABLED = False 
总结:
COOKIES_ENABLED = False 默认是注释的,也就是框架默认是能够使用cookie,框架默认使用的cookie需要在Scrapy.Resuest(url,cookies={})中设置。
   开启 :
COOKIES_ENABLED = False,此时cookie的配置需要在setting.py中的DEFAULT_REQUEST_HEADERR = {}中进行配置。
 
 
    

 

   方式三:DownloadMiddleware中进行设置

第一步:setting.py中打开DOWNLOADER_MIDDLEWARES 的注释,因为设置要在这个类中进行。
DOWNLOADER_MIDDLEWARES = {
   'blog.middlewares.BlogDownloaderMiddleware': 543,
}

第二步:middleware中找到对应的BlogDownloaderMiddleware,其中的函数
    
    def process_request(self,request,spider):

            return None

改为:

     def process_request(self, request, spider):
     
        cookie_from_web = "浏览器中粘贴的Cookies:xx"
        cookies = {}
        for cookie in cookie_from_web.split(";"):
            cookies[cookie.split('=')[0]] = cookie.split('=')[1]
        print(cookies)
        request.cookies = cookies
        return None

第三步:
    启动爬虫程序

  总结:cookie的设置,都是围绕着在请求对象中加入cookie值,怎么加,在哪里加,原则就是在给解析函数返回response的那一次加就可以。

      1:框架的第一次请求时,加入可以,需要重写start_request函数,请求对象参数中加入cookies={}

      2.  在下载中间键,process_request函数中,给request对象加属性值,必须字典格式,request.cookies={}

      3.  setting.py中配置默认的请求头,在默认请求头中添加cookies。

  

---恢复内容结束---

posted on 2019-09-05 16:18  张京墨 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/meloncodezhang/p/11466790.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值