其他分享
首页 > 其他分享> > scrapy框架爬虫案例1-----赶集网

scrapy框架爬虫案例1-----赶集网

作者:互联网

文章目录

1.蜘蛛侠思路:

赶集网
爬取网站的url地址:点击超链接-----赶集网主页-------

步骤一:开始爬虫的第一步应该是要先明确需要爬取的目标网址,这就需要花一些时间了解网站的大致结构,以及明确自己想要获取的数据,并且需要知道这些数据是通过什么方式展现出来的,这就需要查看网站的源代码,如果网站源代码中没有这些数据,就需要考虑其是否是用ajax等方式发送的。

步骤二:观察切换页码时url地址的规律变化

步骤三:观察详情页url地址的规律变化,编写代码

-点击【切换城市】转到有所有城市的主页

点击切换城市

在这里插入图片描述

2.构造爬虫及代码解读

你可以通过cmd构建爬虫,也可以直接使用pycharm中自带的终端构建爬虫
在这里插入图片描述

#创建爬虫项目
scrapy startproject ganji_crawl

#创建爬虫
scrapy genspider ganji anshan.ganji.com

身为一个蜘蛛侠,首先就是需要猥琐,不能让网站知道你是蜘蛛侠,超人都需要隐藏身份,所以我们先写好settings.py文件,把自己伪装成浏览器,让网站不知道我们是蜘蛛侠,然后再写爬虫,以免暴露身份,我把每个文件都分成了单个函数来讲解,这样更方便理解一下,合在一起就是完整的了。

(1)settings.py

爬取一些简单的网站,不需要修改那么多,简单改一下就行了。

LOG_LEVEL='WARNING' #日志的输出等级,不想看那么多日志信息就可以写成WARNING

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'#把自己伪装成浏览器

ROBOTSTXT_OBEY = False #不遵从机器人协议

#把注释去掉就行
ITEM_PIPELINES = {
   'erShouFang.pipelines.ErshoufangPipeline': 300,
}

USER_AGENT随便打开一个网站按F12就能找到,不同浏览器的USER_AGENT是不一样的

在这里插入图片描述

(2)ganji.py

import scrapy
import re
from ..items import ErshoufangItem
class GanjiSpider(scrapy.Spider):
    name = 'ganji' #爬虫名,运行的关键参数
    start_urls = ['http://www.ganji.com/index.htm']

    def start_requests(self):
        for urls in self.start_urls:
            yield scrapy.Request(url=urls,callback=self.parse_province)

通过start_urls 对赶集网主页发起请求。重写 start_requests 方法,一般不直接用parse函数,构造一个新函数会更好;这里通过callback回调了一个新的函数parse_province

 def parse_province(self,response):
        all_city_href = response.xpath('.//div[@class="all-city"]/dl/dd/a/@href').extract()[:1]  #300个城市中选前1个
        for city_href in all_city_href:
            yield scrapy.Request(url=city_href+"zufang",callback=self.parse_detail_urls)

1.定义了一个解析主页所有城市超链接的函数,获取到所有城市的超链接,由于条件有限,这里就只获取第一个url,如果你想一口气干到底,你可以试着把[:1]这个限制去掉… 学到这个思路就好
/
2.extract() 返回的是一个列表extract_first()返回列表第一个元素,get()返回一个字符串
/
3.all_city_href获取到的url是不完整,所以还需要拼接一下才能请求到目标网址
/
4.callback回调函数,通过获取到的url发起新的请求
5.url = http://anshan.ganji.com/zufang/ , zufang=租房,二手房=ershoufang …

通过观察网站,我们发现详情页有我们需要的所有数据,所以这里我直接获取详情页的数据就行了。
我删

在这里插入图片描述在这里插入图片描述

    def parse_detail_urls(self,response):
        print("province_urls:" + response.url)
        all_detail_url = response.xpath('.//dd[@class="dd-item title"]/a/@href').extract()
        for detail_url in all_detail_url:
            if "http" in detail_url:
                yield scrapy.Request(url=detail_url,callback=self.parse_detail)
            if "http" not in detail_url:
                yield scrapy.Request(url="http:"+detail_url,callback=self.parse_detail)
        next_url = response.xpath('.//a[@class="next"]/@href').get()
        if next_url:
            yield scrapy.Request(url=next_url, callback=self.parse_detail_urls)

1.定义一个获取详情页url和实现自动翻页的函数,至于加这个 http 的判断是因为获取的详情页url中有一些是不完整的,所以需要加个判断
2.next_url获取下一页的url地址,通过callback回调自己,实现自动翻页,不需要再去看网站有多少一页,再写个循环了…
3.获取到下一页的url地址,如果这个url存在,就说明有下一页呗。在这里插入图片描述

    def parse_detail(self,response):
        print("detail_ulrs:"+response.url)
        item = ErshoufangItem()  #存储
        item['title'] = response.xpath('normalize-space(.//title/text())').get()
        item['money']  = response.xpath('.//div[@class="price-wrap"]/span[1]/text()').get()
        item['ya_type']  = response.xpath('.//div[@class="price-wrap"]/span[2]/text()').get()
        item['huxing']  = response.xpath('.//ul[@class="er-list f-clear"]/li[1]/span[2]/text()').get()
        mianji  = response.xpath('.//ul[@class="er-list f-clear"]/li[2]/span[2]/text()').get()
        item['zu_type']  =re.findall('\w{2}',mianji)[0]
        item['pingfa']  =re.findall('\w{2}',mianji)[1]
        item['chaoxiang']  = response.xpath('.//ul[@class="er-list f-clear"]/li[3]/span[2]/text()').get()
        louceng = response.xpath('.//ul[@class="er-list f-clear"]/li[4]/span[2]/text()').get()
        item['cengshu']  = re.findall('\d+',louceng)[0]
        item['zhuangxiu']  = response.xpath('.//ul[@class="er-list f-clear"]/li[5]/span[2]/text()').get()
        item['xiaoqu']  = response.xpath('.//ul[@class="er-list-two f-clear"]/li[1]/span[2]/a/span/text()').get()
        item['ditie']  = response.xpath('.//ul[@class="er-list-two f-clear"]/li[2]/div/span/text()').get()
        item['dizhi']  = response.xpath('normalize-space(.//ul[@class="er-list-two f-clear"]/li[3]/span[2]/text())').get()
        item['name']  = response.xpath('.//div[@class="user-info-top"]/div[1]/a/text()').get()
        yield item

1.xpath获取详情页数据就得了,不想多说,逻辑到这里就差不多结束了,剩下的搬砖就行。
2.normalize-space()可以直接去掉\n,\t空格等,就不需要再多写代码去空格了
3.mianji获取到的数据是这样的 “整租 106㎡”,通过正则把他们切分一下,只取数字
4.louceng获取到 “共1层”,通过正则只取数字,到这里就完成了对数据的简单清洗

(3)run.py

from scrapy import cmdline
cmdline.execute('scrapy crawl ganji'.split())

编写运行的类

(4)items.py

需要存储什么就写什么

class ErshoufangItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    money = scrapy.Field()
    ya_type = scrapy.Field()
    huxing = scrapy.Field()
    zu_type = scrapy.Field()
    pingfa = scrapy.Field()
    chaoxiang = scrapy.Field()
    cengshu = scrapy.Field()
    zhuangxiu = scrapy.Field()
    xiaoqu = scrapy.Field()
    ditie = scrapy.Field()
    dizhi = scrapy.Field()
    name = scrapy.Field()

(5)pipelines.py

class ErshoufangPipeline(object):
    def __init__(self):
        # self.connect = pymysql.connect(host='localhost',user='root',passwd='123456',db='ershoufang')
        # self.cursor = self.connect.cursor()
        self.file =codecs.open('./zufang.json','w','utf-8')
        self.dic = ""

1.class ErshoufangPipeline(object):加上(object)
2.self.connect,self.cursor定义mysql数据库连接,可以把数据存储到数据库
3.self.dic = "" 铺垫一下,方便 后面存储为字典

    def process_item(self, item, spider):
        # sql="""
        # insert into table(title,money) values(%s,%s)
        # """
        # self.cursor.execute(sql,(item['title'],item['money']))
        # self.connect.commit()  #提交
        lines = json.dumps(dict(item),ensure_ascii=False)+",\n"
        self.dic+=lines  
        return item
    def close_spider(self,spider):
        self.file.write("[{0}]".format(self.dic[:-2])) 
        self.file.close()
        # self.connect.close()
        # self.cursor.close()

1.self.file.write("[{0}]".format(self.dic[:-2])) ,写入文件,这样可以转化为json格式,不然存储的时候会爆红,不是json格式。
2.[:-2] 就是不要最后的两个字符串 “,\n”

(6)前十条数据

[{"title": "红岭家园 2室1厅1卫,鞍千路 - 赶集网", "money": "900", "ya_type": "半年付", "huxing": "2室1厅1卫", "zu_type": "整租", "pingfa": "66", "chaoxiang": "南北", "cengshu": "22", "zhuangxiu": "简单装修", "xiaoqu": "红岭家园", "ditie": "暂无信息", "dizhi": "立山立山广场 - 鞍千路", "name": "696882"},
{"title": "华润置地广场 1室0厅1卫,建国大道,近民生西路 - 赶集网", "money": "1300", "ya_type": "押一付一", "huxing": "1室0厅1卫", "zu_type": "整租", "pingfa": "50", "chaoxiang": "西", "cengshu": "27", "zhuangxiu": "精装修", "xiaoqu": "华润置地广场", "ditie": "暂无信息", "dizhi": "铁东二一九 - 建国大道,近民生西路", "name": "置家"},
{"title": "解放西路52号小区 1室1厅1卫,解放西路52乙号 - 赶集网", "money": "400", "ya_type": "年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "40", "chaoxiang": "南北", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": "解放西路52号小区", "ditie": "暂无信息", "dizhi": "铁西九街口 - 解放西路52乙号", "name": "hbjes_au6"},
{"title": "铁东一道街 3室2厅1卫 - 赶集网", "money": "1000", "ya_type": "半年付", "huxing": "3室2厅1卫", "zu_type": "整租", "pingfa": "86", "chaoxiang": "东西", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": null, "ditie": "暂无信息", "dizhi": "铁东站前", "name": "王先生"},
{"title": "调军台小区 1室1厅1卫,鞍千路 - 赶集网", "money": "950", "ya_type": "押一付三", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "55", "chaoxiang": "东南", "cengshu": "17", "zhuangxiu": "精装修", "xiaoqu": "调军台小区", "ditie": "暂无信息", "dizhi": "立山立山广场 - 鞍千路", "name": "吴女士"},
{"title": "烈士山社区 1室1厅1卫,胜利南路26号 - 赶集网", "money": "350", "ya_type": "年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "50", "chaoxiang": "西北", "cengshu": "8", "zhuangxiu": "简单装修", "xiaoqu": "烈士山社区(民生东路北)", "ditie": "暂无信息", "dizhi": "铁东二一九 - 胜利南路26号", "name": "蓝眼泪335"},
{"title": "中天社区 3室2厅1卫,铁东二道街 - 赶集网", "money": "1500", "ya_type": "年付", "huxing": "3室2厅1卫", "zu_type": "整租", "pingfa": "15", "chaoxiang": "东南", "cengshu": "6", "zhuangxiu": "精装修", "xiaoqu": "中天社区", "ditie": "暂无信息", "dizhi": "铁东站前 - 铁东二道街", "name": "宁女士"},
{"title": "联盟社区 3室0厅1卫,联盟街11号 - 赶集网", "money": "500", "ya_type": "半年付", "huxing": "3室0厅1卫", "zu_type": "整租", "pingfa": "73", "chaoxiang": "南北", "cengshu": "7", "zhuangxiu": "简单装修", "xiaoqu": "联盟社区", "ditie": "暂无信息", "dizhi": "铁东烈士山 - 联盟街11号", "name": "张女士"},
{"title": "红星小区 2室1厅1卫,红星南街22号 - 赶集网", "money": "375", "ya_type": "押一付三", "huxing": "2室1厅1卫", "zu_type": "整租", "pingfa": "68", "chaoxiang": "南", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": "红星小区", "ditie": "暂无信息", "dizhi": "海城永安路 - 红星南街22号", "name": "杨迎女士"},
{"title": "港丽花园 1室1厅1卫,解放东路150号 - 赶集网", "money": "1200", "ya_type": "半年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "38", "chaoxiang": "南", "cengshu": "33", "zhuangxiu": "精装修", "xiaoqu": "港丽花园", "ditie": "暂无信息", "dizhi": "铁东解放路 - 解放东路150号", "name": "女士"},

3.蜘蛛侠的小Tips(不是黑丝)

写爬虫的时候用debug模式是非常方便的,如果你不知道怎么用,下面可能会帮到你,如果你会,那就算我没说,因为我也不是很会。 右键run.py选择debug ;

在这里插入图片描述

打个断点,至于在什么地方打,比如我想看all_city_href返回了哪些东西,我可以在它后面写个pass打上断点,就不需要print输出了

在这里插入图片描述

1.可以看到很多信息,比如请求的状态啊,url啊,等等等…
2.我们点击text右边的view,可以看到获取的数据(网页源代码)
在这里插入图片描述

这只蜘蛛结束朴实无法一生,想要练习也可以试着去爬取这个网站的更多城市,二手房、厂房啥的j举一反三,不理解的地方可以一起学习交流。代码不完美的地方请多多谅解,多多指教,多多交流。

标签:url,self,item,scrapy,-----,type,response,赶集网
来源: https://blog.csdn.net/dj_hanhan/article/details/115270067