python抓取动态网页(一个爬虫项目目录结构(一)--一个 )

优采云 发布时间: 2022-04-12 00:05

  python抓取动态网页(一个爬虫项目目录结构(一)--一个

)

  我们首先创建一个爬虫项目,这里我们使用scrapy框架来创建它。

  scrapy startproject poco

  然后cd到poco文件夹初始化项目

  scrapy genspider pocoSpider poco.com

  打开项目,项目目录结构如下

  

  我们的爬虫代码写在 pocoSpider 文件中,现在我们打开 网站 来分析网页。

  我们选择人像分类爬行

  可以看到页面上有很多用户id。我们需要先获取每个id的url,然后去详情页抓图。

  右键查看网页源码,发现该页面是js动态生成的网页

  

  并且页面是懒加载的,右键检查元素,查看网络

  

  如果找到请求的图片,请获取请求参数,url地址,复制到postman中调用,成功获取返回数据

  

  分析请求参数,猜测是否可以通过,修改参数得到响应结果,但是修改请求参数后,请求失败,看来直接修改参数的方法无法得到我们需要的url地址。

  让我们随意点击查看网页源代码,看看细节是否也是js动态加载的。

  

  好在我们可以直接在源码中查看我们需要的数据。每张图片的地址在

  在标签里面,就是这么简单。我们可以先爬取这个页面的图片

  import scrapy

from scrapy.crawler import CrawlerProcess

from scrapy.utils.project import get_project_settings

class PocospiderSpider(scrapy.Spider):

name = 'pocoSpider'

allowed_domains = ['poco.com']

start_urls = ['https://www.poco.cn/works/detail?works_id=20992476']

def parse(self, response):

img_list = response.xpath("//img/@data-src").extract()

for img in img_list:

print(img)

if __name__ == "__main__":

process = CrawlerProcess(get_project_settings())

process.crawl('pocoSpider')

process.start()

  不出所料,我们成功拿到了当前id下的所有图片:

  

  现在我们只需要获取所有id对应的url地址并回收请求就可以获取所有图片的地址

  由于无法通过修改参数获取数据,所以我们使用selenium框架来模拟浏览器操作。

  分析页面,每次拉到最后都发送一个请求。我们关闭页面的图片加载以加快访问速度。我们将爬取的数据存储在数据库中,这里我们使用mongod。定义下拉刷新函数,每次刷新后execute_times sleep 0.5秒,以便浏览器渲染页面。这里我们刷新 40 次来获取数据。

  我们在setting.py文件中设置数据库的地址、端口、数据库名

  LOCAL_MONGO_HOST = '127.0.0.1'

LOCAL_MONGO_PORT = 27017

DB_NAME = 'POCO'

  编写 selenium 模拟操作的代码

  执行完之后大概能拿到800多条数据,现在我们重写爬虫代码。

  import pymongo

import scrapy

from scrapy.crawler import CrawlerProcess

from scrapy.utils.project import get_project_settings

from poco.settings import LOCAL_MONGO_HOST,LOCAL_MONGO_PORT,DB_NAME

class PocospiderSpider(scrapy.Spider):

name = 'pocoSpider'

mongo_client = pymongo.MongoClient(LOCAL_MONGO_HOST, LOCAL_MONGO_PORT)

collection = mongo_client[DB_NAME]["idlist"]

id_list = collection.find()

def start_requests(self):

for id in self.id_list:

item = {}

item["folder"]=id["_id"]

item["img_urls"]=[]

yield scrapy.Request(url=id["url"],callback=self.parse_detail,meta={"item":item})

def parse_detail(self, response):

item = response.meta["item"]

img_list = response.xpath("//img/@data-src").extract()

for img in img_list:

if img == "":

continue

img = "https:"+img

item["img_urls"].append(img)

yield item

if __name__ == "__main__":

process = CrawlerProcess(get_project_settings())

process.crawl('pocoSpider')

process.start()

  我们scrapy管道下载图片,我们先写一个管道方法通过id存储图片,我们重写file_path方法修改图片的存储路径

  from scrapy.exceptions import DropItem

from scrapy.pipelines.images import ImagesPipeline

from scrapy import Request

class MyImagesPipeline(ImagesPipeline):

def get_media_requests(self, item, info):

for image_url in item['img_urls']:

referer = image_url

yield Request(image_url,meta={'item':item,'referer':referer})

def file_path(self, request, response=None, info=None):

item = request.meta['item']

folder = item['folder'].strip()

img_name = request.url.split("/")[-1]

filename = u'img/{0}/{1}'.format(folder,img_name)

return filename

def item_completed(self, results, item, info):

image_path = [x['path'] for ok,x in results if ok]

if not image_path:

raise DropItem('Item contains no images')

# item['image_paths'] = image_path

return item

  最后我们修改设置文件中的图片下载中间件和PipeLines

  DOWNLOADER_MIDDLEWARES = {

'poco.middlewares.PocoDownloaderMiddleware': 543,

}

IMAGES_STORE=r'E:\\'

IMAGES_EXPIRES = 30

# Enable or disable extensions

# See https://doc.scrapy.org/en/latest/topics/extensions.html

#EXTENSIONS = {

# 'scrapy.extensions.telnet.TelnetConsole': None,

#}

ITEM_PIPELINES = {

'poco.pipelines.MyImagesPipeline': 300,

}

CONCURRENT_REQUESTS = 32

DOWNLOAD_DELAY = 0.1

# Configure item pipeli

  至此,poco网站的爬虫已经写好,代码运行完毕,图片爬取成功,按照id分类存储

  

  后记:其实爬虫代码还是有bug的。当爬虫运行 10 分钟,没有爬取到 id 时,会自动停止。仔细查看代码,发现一个mongodb的坑。那是

   collection = mongo_client[DB_NAME]["idlist"]

id_list = collection.find()

  当调用 db.采集.find() 时,它返回的不是所有数据,而是一个“光标”。它的默认行为是:首先在数据库中查询 101 个文档,或者 1 MB 的文档,这取决于首先满足哪个条件;然后每次光标用完文档时,查询 4 ​​MB 的文档。此外,find() 的默认行为是返回一个在 10 分钟不活动后超时的游标。如果 10 分钟内没有处理请求,那么我们将无法获取剩余的 url,因此爬虫将停止。

  解决方法也很简单,就是直接将id_list中的数据存入开头的list中。

  # -*- coding: utf-8 -*-

import pymongo

import scrapy

from scrapy.crawler import CrawlerProcess

from scrapy.utils.project import get_project_settings

from poco.settings import LOCAL_MONGO_HOST,LOCAL_MONGO_PORT,DB_NAME

class PocospiderSpider(scrapy.Spider):

name = 'pocoSpider'

mongo_client = pymongo.MongoClient(LOCAL_MONGO_HOST, LOCAL_MONGO_PORT)

collection = mongo_client[DB_NAME]["idlist"]

id_list = collection.find()

ids=[]

for id in id_list:

ids.append(id)

def start_requests(self):

for id in self.ids:

item = {}

item["folder"]=id["_id"]

item["img_urls"]=[]

yield scrapy.Request(url=id["url"],callback=self.parse_detail,meta={"item":item})

def parse_detail(self, response):

item = response.meta["item"]

img_list = response.xpath("//img/@data-src").extract()

for img in img_list:

if img == "":

continue

img = "https:"+img

item["img_urls"].append(img)

yield item

if __name__ == "__main__":

process = CrawlerProcess(get_project_settings())

process.crawl('pocoSpider')

process.start()

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线