scrapy新手入门爬虫(链家小区信息)

新手python3自学爬虫1个星期,期间遇到各种坑,还参考各种文章,以及让高手远程帮助,总算完成了简单的爬虫,现在总结一下各种经验,文章里可能有描述的不对的地方,请各位指正
开发的工具:python36,scrapy,beautifulsoup,pymysql
安装问题细节可以看一下别的教程,我这里大致说一下遇到的坑

首先python安装的时候如果你没有勾环境变量 ,需要去环境变量path里设置,下面是我的变量,就是装python的地址,然后后面的scripts也要声明一下,可以方便以后用pip装东西。
python安装验证
验证的话可以在开始-附件-运行里输入cmd,然后输入python,如果出现python版本,说明装好了。
pip怎么用?
直接开始-附件-运行里输入cmd,然后输入如:pip install Scrapy,就可以看到模块会自动安装。如果运行的时候错误,可以去环境变量里看看scripts是否加进去了
我的path E:\Python\Python36;E:\Python\Python36\Scripts

scrapy可以用pip install Scrapy
scrapy装的时候可能会遇到 error: Microsoft Visual C++ 14.0 is required
下载twisted,ctrl+f找到对应的版本:http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
还会遇到 no module named win32api
原因是缺少win32,到 http://sourceforge.net/projects/pywin32/files/
mysql安装,注意要用小写,还可以用其他的mysql相关模块,反正python3里这个肯定是没问题
pip install pymysql
继续装 pip install beautifulsoup4
一般如果还遇到什么问题,可以看看cmd里红字的提示缺少什么,百度一下就ok
下面正式写程序
在cmd里输入scrapy startproject lianjia创建scrapy爬虫工程,比如我要建在d盘的根目录,在命令行输入cd e: 回车scrapy startproject lianjia回车,就创建好了,目录结构为D:\lianjia\lianjia\spiders,然后在spiders文件夹里创建lianjia.py文件


#导入第三方模块
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
import pymysql
#name为一会儿要运行的爬虫名,格式为:scrapy crawl lianjia

#allowed_domains为域名,控制爬虫的爬取范围,但是这里有可能会产生一个bug,某些情况域名限制了数据的输,只能传一条,比如for i in['aaa','bbb'],print(i),只会拿到一个aaa的值,解决方就是在yield后面加上dont_filter=True,让域的限制消失

#start_urls 开始页,但是本次爬虫并没有用到
#上面三个应该是scrapy的格式
#server及sec是为了爬取设置的网址

class lianjia(scrapy.Spider):
    name = "lianjia"
    allowed_domains = ['http://sh.lianjia.com']
    start_urls = ['http://sh.lianjia.com/zufang/']
    server = 'http://sh.lianjia.com/xiaoqu/d'
    sec = 'http://sh.lianjia.com'
#注意第一个函数名一定要为parse,response就是从上一项拿到的值,当然也可以改成aaaa这种都没问题。然后可以打印一下respense,看一下值是什么。<200 http://sh.lianjia.com/zufang/>,一般来说如果要用到首页的话下面就可以直接用xpath解析了

#page_num为需要爬取的页数,然后for历遍一下,并拼在server的后面,所以能得到的值为http://sh.lianjia.com/xiaoqu/d1,注意拼的时候i一定要用str先转成字符串类型,不转的话是数字类型会报错,可以print (link)打印一下看网页内容

#yield scrapy.Request就是一个传递的参数有下面的只介绍3个,url=需要传递的值,callback=传递给哪个函数,dont_filter=True不启用域的限制

    def parse(self, response):
        page_num = 1
        for i in range(1, page_num + 1):
            link = self.server + str(i)
            yield scrapy.Request(url=link, callback=self.parse2, dont_filter=True)
#zu_fang解析parse传过来的各种网页,就是http://sh.lianjia.com/xiaoqu/d1,如果不清楚的话可以打开网页,通过检查方式看,response.xpath就是用xpath模式解析,//li就是li开头/div/a是li后面的目录结构,然后通过@来获取a里的href的值(如果要取文本的话可以用text()),extract()全部显示[:1]取第一个找到的,这部分可以单独百度一下xpath

#之后的解释都和上面是一样的,就是获取lianjia上的d1页面上每一个小区里的链接地址

    def parse2(self, response):
        zu_fang = response.xpath('//li/div/a/@href').extract()[:1]
        for link in zu_fang:
            linka = self.sec + link
            print (linka)
            yield scrapy.Request(url=linka, callback=self.parse3, dont_filter=True)
#最后根据解析的地址找到相关的的标签,这里用到的第三方类beauifulsoup,解释一下逻辑,拿到从parse2传递过来的值,通过xpath解析,然后转换成beautifulsoup格式,下面的都是通过soup去找的各种字段类型,具体的可以看一下soup的各种文档

#我以这条为例说一下意思,soupa = soup.find_all('div', class_="nav-container detail-container")[0]
#soup.find_all找soup变量的所有div标签,并且class="nav-container detail-container"的相关内容[0]表示取拿到的第一个值

#district = soupa.span.span.string,找到soupa下的第一个span标签,并再往下一层在span的标签里找第一个span标签,然后用string把值显示出来

#replace('\\n', '').replace('\\t', '').strip() 去除字段中的\n,\t及空格的意思,这里用\\就是转义的意思,\\=\,或者也可以用r,如replace(r'\n', '').replace(r'\t', '').strip()

    def parse3(self, response):
        zufang = response.xpath('//body').extract()
        soup = BeautifulSoup(str(zufang), 'lxml')

        village = soup.h1.string
        soupa = soup.find_all('div', class_="nav-container detail-container")[0]
        district = soupa.span.span.string
        address = soupa.span.find_all('span')[1].string
        price = soup.find_all('div', class_="item col1")[0].span.string.replace('\\n', '').replace('\\t', '').strip()
        type = soup.find_all('div', class_="col-2 clearfix")[0].li.span.string.replace('\\n', '').replace('\\t', '').strip()
        age = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span')[2].string.replace('\\n', '').replace('\\t','').strip()
        fee = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[2].string.replace('\\n','').replace('\\t', '').strip()
        estate = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[3].string.replace('\\n','').replace( '\\t', '').strip()
        developer = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[4].string.replace( '\\n', '').replace('\\t', '').strip()
        district2 = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[5].string
        ring = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[6].string.replace('\\n','').replace('\\t', '').strip()
 # 打开数据库连接,charset="utf8"必须加,不然如果爬到的是中文字,插不进数据库
        db = pymysql.connect("数据库地址", "用户", "密码", "库名", charset="utf8")
        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # SQL 插入语句,如果插入遇到问题可以看一下表设置的最大字段长度是否过短
        sql = """INSERT INTO village_info_lianjia(village,district,address,price,type,age,fee,estate,developer,district2,ring,source)
                 VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')"""%(village,district,address,price,type,age,fee,estate,developer,district2,ring,'lianjia')
        try:
            # 执行sql语句
            cursor.execute(sql)
            # 提交到数据库执行
            db.commit()
        except:
            # 如果发生错误则回滚
            db.rollback()
    #
    #关闭数据库连接
        db.close()

完整的数据代码




# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
import pymysql

class lianjia(scrapy.Spider):
    name = "lianjia"
    allowed_domains = ['http://sh.lianjia.com']
    start_urls = ['http://sh.lianjia.com/zufang/']
    server = 'http://sh.lianjia.com/xiaoqu/d'
    sec = 'http://sh.lianjia.com'

    def parse(self, response):
        page_num = 1
        for i in range(1, page_num + 1):
            link = self.server + str(i)
            yield scrapy.Request(url=link, callback=self.parse2, dont_filter=True)

    def parse2(self, response):
        zu_fang = response.xpath('//li/div/a/@href').extract()[:1]
        for link in zu_fang:
            linka = self.sec + link
            print (linka)
            yield scrapy.Request(url=linka, callback=self.parse3, dont_filter=True)

    def parse3(self, response):
        zufang = response.xpath('//body').extract()
        soup = BeautifulSoup(str(zufang), 'lxml')

        village = soup.h1.string
        soupa = soup.find_all('div', class_="nav-container detail-container")[0]
        district = soupa.span.span.string
        address = soupa.span.find_all('span')[1].string
        price = soup.find_all('div', class_="item col1")[0].span.string.replace('\\n', '').replace('\\t', '').strip()
        type = soup.find_all('div', class_="col-2 clearfix")[0].li.span.string.replace('\\n', '').replace('\\t', '').strip()
        age = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span')[2].string.replace('\\n', '').replace('\\t','').strip()
        fee = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[2].string.replace('\\n','').replace('\\t', '').strip()
        estate = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[3].string.replace('\\n','').replace( '\\t', '').strip()
        developer = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[4].string.replace( '\\n', '').replace('\\t', '').strip()
        district2 = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[5].string
        ring = soup.find_all('div', class_="col-2 clearfix")[0].find_all('span', class_='other')[6].string.replace('\\n','').replace('\\t', '').strip()


        db = pymysql.connect("数据库地址", "用户", "密码", "库名", charset="utf8")

        cursor = db.cursor()

        sql = """INSERT INTO village_info_lianjia(village,district,address,price,type,age,fee,estate,developer,district2,ring,source)VALUES('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')"""%(village,district,address,price,type,age,fee,estate,developer,district2,ring,'lianjia')
        try:

            cursor.execute(sql)

            db.commit()
        except:

            db.rollback()

        db.close()

mysql建表命令

CREATE TABLE `village_info_lianjia` (
  `village` varchar(30) DEFAULT NULL,
  `district` varchar(30) DEFAULT NULL,
  `address` varchar(300) DEFAULT NULL,
  `price` varchar(30) DEFAULT NULL,
  `type` varchar(30) DEFAULT NULL,
  `age` varchar(30) DEFAULT NULL,
  `fee` varchar(30) DEFAULT NULL,
  `estate` varchar(30) DEFAULT NULL,
  `developer` varchar(30) DEFAULT NULL,
  `district2` varchar(30) DEFAULT NULL,
  `ring` varchar(300) DEFAULT NULL,
  `source` varchar(30) DEFAULT NULL
)

最后忘记说了page_num = 1 是页数。1代表http://sh.lianjia.com/xiaoqu/d1,2代表http://sh.lianjia.com/xiaoqu/d2等以此类推
lianjia的网址每页都有20条房子数据,我代码只取了第一条,所以如果你爬完整的话,需要把1改成20
如:
zu_fang = response.xpath(‘//li/div/a/@href’).extract()[:20]

最后再说一下scrapy执行命令
cd进链家的目录
比如我的目录结构是D:\lianjia\lianjia\spiders
那我在cmd的时候就先cd D:回车cd lianjia回车,直接输入scrapy crawl lianjia
其中lianjia是爬虫的name
name = “lianjia”

你可能感兴趣的:(python3)