关于爬虫中几个常用库的使用方法总结

时间:2023-01-05 15:17:21

关于爬虫中几个常用库的使用方法总结

  • 学了半个多月的爬虫了,用这个案例总结一下各个爬虫库的用法。当然后面还有更重要和更好用的方法,再等后面学到,再做总结了。

1. 目标

  • 这个题目的要求很简单,用已学的方法,爬取某知名二手房源的信息。因为涉及到一些敏感的信息,只要求获取只个简单的字段即可。

1.1 爬取某知名网站的相关信息

  • 具体如下:
    • (1)爬取某网的房源信息,包括“标题,位置,户型,总价,单价”几个信息的收集并保存。
    • (2)网址是:https://cs.lianjia.com/ershoufang/

1.2 信息库及类的导入

  • 下面分几种方法解决这个答题,所以用到的库有如下几种:
    • requests、lxml的xpath对象方法、re正则表达式、BeautifuSoup对象方法、pyquery对象方法、parsel的Selector方法
  • 有时候,获取源代码和解析数据,是好几种方法一起来解决,在下面的几个解决方案中,都有提到。

2. 网页分析

  • 接下来,就是网页的分析。打开网页如下: 关于爬虫中几个常用库的使用方法总结
  • 再往下拖动,看到该页有30条信息,下面只看到局部的几条信息。其中每一条信息用蓝色方框圈起来,而红色方框圈起来的,是一条广告信息,是无用信息,后面在解析的时候给予剔除。 关于爬虫中几个常用库的使用方法总结

2.1 伪装问题

  • 根据政策法规的要求,我们不能随便用不正当手段爬取绝大多数网站的有用信息。不过动机单纯、行为正常,且没有恶意,出于研究目的,在控制好频率的情况下,爬取一些网站公开内容,是可以的。
  • 但是绝大多数网站都有反爬机制,它不管你的动机如何,一旦越限,它就会毫不客气的唯你是问,让你百口莫辩。
  • 因此,我们在这里,也了解一下这次这个网站的Robots协议,方法如下:
    • 打开https://cs.lianjia.com/robots.txt,得到如下robots内容:
      User-agent: Baiduspider
      Allow: *?utm_source=office*
      
      User-agent: *
      sitemap: https://cs.lianjia.com/sitemap/cs_index.xml
      Disallow: /rs
      Disallow: /huxingtu/p
      Disallow: /user
      Disallow: /login
      Disallow: /userinfo
      Disallow: *?project_name=*
      Disallow: *?id=*
      Disallow: *?house_codes=*
      Disallow: *?sug=*
      
    • 以上可以看到,我们今天所要爬取的目录ershoufang是被允许爬取的。
    • 再用如下方法: 关于爬虫中几个常用库的使用方法总结
    • 可以看到,这个网站的robots.txt文件是允许爬虫抓取ershoufang里面的数据的。
    • 基于以上原因,我们只加一个请求头,是可以了。方法前面写过:右击网页空白处“检查”——>“Network”——>Filter(筛选器)——>Doc(文档)——>刷新网页——>选择Name(名称)下的记录——>再找到右侧最底部,就找到User-Agent字符串头。复制出来 做成字典的模样,定义一个headers即可。关于爬虫中几个常用库的使用方法总结

2.2 元素选取

  • 上图说明,如下: 关于爬虫中几个常用库的使用方法总结
  • 左侧小箭头就是选择器,使用的时候点它一下,然后去网页里面晃动几下,就看到一片区域对应一大段代码。这里,我们看到<ul>标签里,就对应本页所有的房源信息,就是<ur>下的<li>标签,仔细数一下,一共30条记录,对应30条房源,当然,其中第6条是广告,不过在爬虫库解析下,得到的数据是一一对应为30条的。
  • 每一条的<div>标签下,都包含我们想要的数据,截图如下: 关于爬虫中几个常用库的使用方法总结

2.3 分页面分析

  • 页面到最底部,有1到100页码,所以想抓取的信息可以有100页300条,本例只取前5页,用for循环实现翻页取信息,在下面代码实现。因为在翻页的过程中,地址栏里出现/pg2/、/pg3/的字样。所以在定义网址的时候,用如下方法:
    def __init__(self, num):
            self.url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(num)
    
     # 爬取5页的数据
    for n in range(1, 6):
        print('正在爬取第{}页'.format(n))
        spider = LianJian_changsha(n)
    

2.3 爬虫库的选用

  • 一般情况下,爬取数据不是太多的时候,用requests库结合一般的方法就能完成,大型数据获取并分析的情况,要用到更高级的方法。所以根据需求选择合适的爬虫库,也应该知道。因为是初学,对于下面的分析不一定准确,欢迎编程经验多的大佬们,批评指正。

2.3.1 保存文本的方法

  • 除了即时打印输出到控制台的办法外,保存爬虫数据最基础的自然是文本文件了。

  • 方法很简单,就是用操作文件和文件夹的办法,实现保存。涉及到路径的时候,要导入os库,然后有两种书写格式,如下 :

    # 第一种方法,后面需要手动close关闭文件对象
    filename = open('file1.txt','w')
    filename.close()
    

    # 第二种方法,后面不需要带close方法,也可以确保文件正常关闭
    with open('file2.txt','w') as f2:
    		f2.write(data)
    

2.3.2 保存二进制的方法

  • 上面提到,文本文件的获取过程,首先是获取源代码,再解析筛选得到文本内容,如果想要的数据变量为data的话,可以用text方法得到,如print(data.text)。而要得到图像或者音视频数据的话,就要先得到它们的二进制数据,用content方法,如print(data.content)。
  • 后面例子中,会经常遇到,爬虫学习的过程中,有你有我,我们一起作伴,慢慢走在路上,就会不知疲倦。

2.3.3 哪个更简单

  • 哪个爬虫的库用起来更简单,也要看获取到的网页格式,像本节提到的例子,用lxml里面的xpath方法比较简单。我说的简单,其实就是容易理解和使用,真正书写代码也可能很繁琐。我们在验证结果的时候,要不时的print一下,以此纠正解析得到的数据是多了还是少了。
  • 如果按照书写简洁来作为简单的话,目前学到的bs4和pyquery库就特别简单。很多时候,感觉比正则表达式的方法还要简单。

2.3.4 哪个更效率

  • 效率最高的爬虫方法,目前不敢定论,但是感觉requests以后,再用xpath方法是最麻烦的,遇到源代码中的多个ul列表、li列表、span列表等,还有各种空格乱码时,特快灵麻烦。在掌握了好的方法和熟练运用正则表达式之后,xpath能不用就不用,但是本节还是以这个为例讨论,毕竟这个是基础。
  • 我感觉,bs4和pyquery效率就蛮高,但是感觉目前掌握的方法中parsel方法更胜一筹。
  • 除了上面提到的,还有一个压箱底的东西,那就是CSS选择器,这个东西在几个重要的爬虫库里面经常用到,而且经常一步到位,实在是手术刀式的工具。

2.4 数据保存的问题

    • 爬虫得到的结果,才是我们想要的。有的不是太重要,可以略加展示或保存。有的结果很重要,这些数据就要用相当可靠的方式保存起来,以供后期的分析和使用。

2.4.1 打印输出

  • 这是最简单的展示方法,只是在控制台打印输出一下,看完就消失,对于不是重要的信息,完全够用了。

2.4.2 文本保存

  • 爬虫获取的数据,以最简单的文本格式保存,上面已经提到,后面复习爬虫库的使用时,还会再提到 ,在此不再赘述。

2.4.3 csv文件存储

  • 我用excel格式保存数据的时候,遇到了不能保存翻页信息的情况,当掌握了csv文件存储方法后,一下子感觉轻松解决了。因为csv文件完全可以用excel表格的形式打开,而且更简洁效率。

2.4.4 MySql存储

  • 这个数据库用来存储数据,是比较哪个和哪个的(敏感词&^%#@¥),不光是因为MySql在大型程序中应用,关键是很多爬虫得到的数据足够重要,用MySql保存也足够正式。这为后面的数据分析作了良好的支持。

2.4.5 MongoDB存储

  • 这个数据库是非关系型数据库,其内容存储的形式累死JSON对象。这次也学习一下这个数据库的保存方式,这之前要从头学习它的安装、初始化和建表、插入数据的方法。

3. 方法罗列

  下面的几种爬虫方法是目前我个人学到的,为了帮助记忆理解,在此加以记叙和总结。其中发现,各种方法很少有单独存在的情况,一是因为一个方法完成不了,另一个原因是,几种方法的组合使用,效率大大提高。

3.1 requests方法

  • 这个方法,是后面xpath方法、re正则表达式的前提条件。因为都用requests模块的get请求方法和post请求方法得到整个网页源代码之后,再进行xpath解析和正则匹配的。实际用法,在后面放上案例进行学习。

3.2 lxml的xpath方法

  • 按照上面的分析,用代码实现目标要求。全部代码如下:
    # -*- coding:utf-8 -*-
    """
        # @Time:2022/12/19 0019 13:53
        # @Author:晚秋拾叶
        # @File:链家长沙房源.py
        # @PyCharm之Python
        # 完成“标题,位置,户型,总价,单价”几个信息的收集并保存
    """
    import os
    import csv
    import requests
    from lxml import etree
    
    
    class LianJian_changsha(object):
        def __init__(self, num):
            self.url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(num)
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54',
                
            }
    
        ''' 1. 发起请求并获取数据 '''
    
        def get_data_index(self):
            # 可以使用urlli库里的方法from urllib.request import Request
            # 即用urllib中的request模块里的Request类定义解析的网页数据,
            # 不过需要用read()读取二进制内容,再用decode('utf-8')转为Unicode编码
            # 所以不如requests库来得方便
            """ (1)用到第一个库requests的get方法,获取总的网页源代码 """
            resp = requests.get(self.url, headers=self.headers)
            resp.encoding = 'utf-8'
            if resp.status_code == 200:
                return resp.text
            else:
                return None
    
        ''' 2. 把得到的网页文本信息进行解析 '''
    
        def parse_data_index(self, resp):
            # 实例化一个etree的HTML类对象,这也是后面xpath解析的对象
            """ (2)用到第二个库lxml里的etree模块,构造一个xpath对象 """
    
            html_xpath = etree.HTML(resp)
    
            # 找到包含房源信息的总模块,可以看作为列表形式
            """ (3)xpath方式完成解析数据 """
            sellListContent = html_xpath.xpath('//ul[@class="sellListContent"]//li')
            list_context = []
            i = 0
            for data in sellListContent:
                title = data.xpath('.//div[@class="title"]/a/text()')[0]
                position = ','.join(data.xpath('./div[1]/div[2]//a/text()')).replace(' ', '')
                houseInfo = data.xpath('.//div[@class="houseInfo"]/text()')[0].replace('|', ',').replace(' ', '')
                priceInfo = data.xpath('.//div[contains(@class,"totalPrice")]/span/text()')[0] + "万元"
                unitPrice = data.xpath('.//div[@class="unitPrice"]/span/text()')[0]
    
                dict_data = {'标题': title, '位置': position, '户型': houseInfo, '总价': priceInfo, '单价': unitPrice}
                i += 1
                print(f"现在是第{i}条数据")
                print(dict_data)
                list_context.append(dict_data)
            return list_context
    
        def write_data(self, resp):
            # 判断是否已经有这个csv文件,如果有,则不再添加标头,只追加记录
            if os.path.exists("LianJia_changsha.csv"):
                with open("LianJia_changsha.csv", "a", newline='', encoding='utf-8') as f:
                    fields = ['标题', '位置', '户型', '总价', '单价']
                    writer = csv.DictWriter(f, fieldnames=fields)
                    for data in self.parse_data_index(resp):
                        writer.writerow(data)
            else:
                with open("LianJia_changsha.csv", "w", newline='', encoding='utf-8') as f:
                    fields = ['标题', '位置', '户型', '总价', '单价']
                    writer = csv.DictWriter(f, fieldnames=fields)
                    writer.writeheader()
                    for data in self.parse_data_index(resp):
                        writer.writerow(data)
    
        """ 3. 把上面方法整合起来完成业务逻辑"""
    
        def run(self):
            resp = self.get_data_index()  # 获取网页信息
            self.write_data(resp)
    
    
    if __name__ == '__main__':
        # 爬取5页的数据
        for n in range(1, 6):
            print('正在爬取第{}页'.format(n))
            spider = LianJian_changsha(n)
            spider.run()
    
    
    • 掌握了合适的方法,加以处理,就得到了想要的数据,其中的带广告的那个li标签,也合理的规避了。上面这个方法用了csv格式保存

3.3 re正则表达式

  • 下面是用re正则表达式的方法完成问题解决。还是先用xpath缩小一下源代码的范围,做出<li>标签的列表来。在用re处理字符串的过程中,遇到了检查元素的代码和xpath获取源代码不一样的情况。如图:
  • 检查元素的代码: 关于爬虫中几个常用库的使用方法总结
  • 由此可见,想要正则匹配到我们需要的数据,只有得到真正的源代码才能够获取。下面用requests和xpath方法得到li标签列表。 关于爬虫中几个常用库的使用方法总结
  • 上面截图是爬取到的li标签列表,复制出一个li标签到http://www.wetools.com/html-formatter网站,稍微纠正下,再复制到记事本里面,更容易寻找对应的数据。 关于爬虫中几个常用库的使用方法总结
  • 下面把得到的源代码放到记事本中。 关于爬虫中几个常用库的使用方法总结
  • 再把包含一个数据的一大段代码复制到VSCode程序里,加以正则处理。

关于爬虫中几个常用库的使用方法总结

  • 注意想要的数据用(.*?)代替,然后方便用group(n)的方法得到。 关于爬虫中几个常用库的使用方法总结
  • 在保存为字符串形式的时候,需要一些转换字典为字符串的情况,代码中已经作了注释。
  • 最后,我把这个用记事本保存成txt文件,整个代码如下:
    # -*- coding:utf-8 -*-
    """
        # @Time:2022/12/19 0019 13:53
        # @Author:晚秋拾叶
        # @File:链家长沙房源.py
        # @PyCharm之Python
        # 完成“标题,位置,户型,总价,单价”几个信息的收集并保存
    """
    import os
    import re
    import json
    import requests
    from lxml import etree
    
    
    class LianJian_changsha(object):
        def __init__(self, num):
            self.url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(num)
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54',
                
            }
    
        ''' 1. 发起请求并获取数据 '''
    
        def get_data_index(self):
            # 可以使用urlli库里的方法from urllib.request import Request
            # 即用urllib中的request模块里的Request类定义解析的网页数据,
            # 不过需要用read()读取二进制内容,再用decode('utf-8')转为Unicode编码
            # 所以不如requests库来得方便
            """ (1)用到第一个库requests的get方法,获取总的网页源代码 """
            resp = requests.get(self.url, headers=self.headers)
            resp.encoding = 'utf-8'
            if resp.status_code == 200:
                return resp.text
            else:
                return None
    
        ''' 2. 把得到的网页文本信息进行解析 '''
    
        def parse_data_index(self, resp):
            # 进一步筛选想要的源代码内容,缩小范围
            """ (2)还是用xpath定位好范围 """
            html_xpath = etree.HTML(resp)
            sellListContent = html_xpath.xpath('//ul[@class="sellListContent"]//li')
           
            try:
                """ (3)re正则方式完成解析数据 """
                for data in sellListContent: 
                    # 转换为字符串,以便后面进行正则获取  
                    htmlStr = etree.tostring(data,encoding="utf-8").decode()
                
                    title_pattern = re.compile('<div\sclass="title">.*?data-sl="">(.*?)</a>', re.S)
                    position_pattern = re.compile('class="positionIcon".*?region">(.*?)</a>.*?target="_blank">(.*?)</a>', re.S)
                    houseInfo_pattern = re.compile('class="houseIcon".*?/>(.*?)</div>', re.S)
                    priceInfo_pattern = re.compile('class="totalPrice totalPrice2">.*?class="">(.*?)</span>.*?</i>', re.S)
                    unitPrice_pattern = re.compile('class="unitPrice.*?<span>(.*?)</span>', re.S)
                    title = re.search(title_pattern, htmlStr).group(1)
                    position = re.search(position_pattern, htmlStr)
                    positiongroup = position.group(1) + position.group(2)
                    houseInfo = re.search(houseInfo_pattern, htmlStr).group(1)
                    priceInfo = re.search(priceInfo_pattern, htmlStr).group(1) +"万元"
                    unitPrice = re.search(unitPrice_pattern, htmlStr).group(1)
                    # 注意,下面字典处理的时候,一定要用""而不能用''
                    yield {"标题": title, "位置": positiongroup, "户型": houseInfo, "总价": priceInfo, "单价": unitPrice}    
            except IndexError:
                pass
        def write_data(self, content):
            with open('链家长沙房源信息.txt', 'a',encoding='utf-8') as f:
                # 因为获取的数据是字典类型,转换为字符串写入文本文件,而且还不能显示为ascii,否则看不到汉字
                f.write(json.dumps(content,ensure_ascii=False)+"\n")
    
        """ 3. 把上面方法整合起来完成业务逻辑"""
        def run(self):
            resp = self.get_data_index()  # 获取网页信息
            for data in self.parse_data_index(resp):
                print(data)
                self.write_data(data)
    
    
    if __name__ == '__main__':
        # 爬取5页的数据
        for n in range(1, 6):
            print('正在爬取第{}页'.format(n))
            spider = LianJian_changsha(n)
            spider.run()
    
    
  • 完成后,效果如下: 关于爬虫中几个常用库的使用方法总结

3.4 BeautifuSoup方法

  • 再学习一下bs4的写法。
  • 这个库的功能很强大,方法有节点选择器,有方法选择器find_all,再加上强大的CSS选择器。用了更简短的代码,完成了既定目标。完整代码如下:
    # -*- coding:utf-8 -*-
    """
        # @Time:2022/12/19 0019 13:53
        # @Author:晚秋拾叶
        # @File:链家长沙房源bs4.py
        # @PyCharm之Python
        # 完成“标题,位置,户型,总价,单价”几个信息的收集并保存
        # 这次用excel方法保存
    """
    import requests
    import openpyxl
    from bs4 import BeautifulSoup
    
    
    class LianJian_changsha(object):
        def __init__(self):        
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54',
            }       
    
    
        ''' 1. 发起请求并获取数据 '''
    
        def get_response(self,url):
            # 可以使用urlli库里的方法from urllib.request import Request
            # 即用urllib中的request模块里的Request类定义解析的网页数据,
            # 不过需要用read()读取二进制内容,再用decode('utf-8')转为Unicode编码
            # 所以不如requests库 来得方便
            """ (1)用到第一个库requests的get方法,获取总的网页源代码 """        
            resp = requests.get(url, headers=self.headers)
            resp.encoding = 'utf-8'
            if resp.status_code == 200:
                return resp.text
            else:
                return None
    
        ''' 2. 把得到的网页文本信息进行解析 '''
        def parse_data(self):
            data_list = []
            for i in range(1,6):
                # 因为要分布保存到excel中,而且用的是openpyxl方法,所以把页面地址的更迭放在这里
                url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(i)
                resp = self.get_response(url)
                # 进一步筛选想要的源代码内容,缩小范围
                """ (2)这个库的功能强大,用select方法和节点选择器,加上CSS选择器,代码简洁好用 """
                soup = BeautifulSoup(resp, 'lxml')
                sellListContent = soup.select("ul li .info.clear")
                i = 0
                # 解析并提取数据            
                for data_div in sellListContent:
                    # 下面的[0]用法,其实是列表索引,与xpath的位置选择不一样
                    title= data_div.select("a")[0].text
                    position = data_div.select("div .positionInfo")[0].text
                    houseInfo = data_div.select("div .houseInfo")[0].text
                    priceInfo = data_div.select(".totalPrice.totalPrice2 span")[0].text + "万元"
                    unitPrice = data_div.select(".unitPrice")[0].text  
                    data = [title,position,houseInfo,priceInfo,unitPrice]
                    i += 1
                    print(f"现在是第{i}条")
                    print(data)
                    data_list.append(data)
            return data_list
        
    
        def save_to_excel(self):
            datas = self.parse_data() #数据,也就是上面获取到的嵌套列表
            print('开始保存...')
            # 表头
            excel_header = ['标题','位置','户型','总价','单价']
    
            # 创建excel表格并写入表头
            wb = openpyxl.Workbook()
            ws = wb.create_sheet(title='链家长沙房源', index=0)
            wb.remove(wb['Sheet']) # 删除原来的表
            ws.append(excel_header) # 写入表头       
    
            # 遍历数据
            for data in datas:
                # 将每行数据追加到表格
                ws.append(data)
    
            # 保存表格
            wb.save('链家长沙房源.xlsx')
        """ 3. 把上面方法整合起来完成业务逻辑"""
        def run(self):
            self.parse_data()  # 获取网页信息
            self.save_to_excel()
            print("保存完成。")
          
    
    
    if __name__ == '__main__':    
        spider = LianJian_changsha()
        spider.run()
    
    
  • 效果如图。 关于爬虫中几个常用库的使用方法总结

3.5 pyquery方法

  • 这次保存数据信息,我用MySQL的方法,以进一步掌握数据库的使用方法。

3.5.1安装MySQL

  • 这里登录https://dev.mysql.com/downloads/mysql/,选择Microsoft Windows打开如下页面,点击下面的Download按钮。 关于爬虫中几个常用库的使用方法总结

  • 这是一个免安装的数据库程序,然后把数据库包解压到E盘,如图。 关于爬虫中几个常用库的使用方法总结

  • 其中,my.ini是自己创建的配置文件,保存到数据库当前目录,内容如下:

    [client]
    # 设置mysql客户端默认字符集
    default-character-set=utf8
     
    [mysqld]
    # 设置3306端口
    port = 3306
    # 设置mysql的安装目录
    basedir=E:\mysql8.0
    # 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
    # datadir=E:\mysql8.0\\sqldata
    # 允许最大连接数
    max_connections=20
    # 服务端使用的字符集默认为8比特编码的latin1字符集
    character-set-server=utf8
    # 创建新表时将使用的默认存储引擎
    default-storage-engine=INNODB
    
  • 接下来我们来启动下 MySQL 数据库:

  • 管理员身份打开 cmd 命令行工具,切换目录:

关于爬虫中几个常用库的使用方法总结

3.5.1 初始化数据库

~~~
mysqld --initialize --console
~~~

执行完成后,会输出 root 用户的初始默认password,如:

...
2023-01-04T02:35:05.464644Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: APWCY5ws&hjQ
...

APWCY5ws&hjQ 就是初始password,后续登录需要用到,你也可以在登陆后修改password。

mysqladmin -u用户名 -p旧密 password 新密 我这里没有成功,也没找原因,直接去掉旧密,再执行后,要求输入password的时候,输入完就更新成功了。最后显示OK。

  • 安装数据库,下面也是在bin目录下执行。

    mysqld install
    
  • 安装结束后启动服务即可, 启动服务命令如下:

    net start mysql
    
  • 登陆MySQL

    当 MySQL 服务已经运行时, CD到bin目录,打开命令提示符, 输入以下格式的命名:

    mysql -h 主机名 -u 用户名 -p	
    
    • -h : 指定客户端所要登录的 MySQL 主机名, 登录本机(localhost 或 127.0.0.1)该参数可以省略;
    • -u : 登录的用户名;
    • -p : 告诉服务器将会使用一个password来登录, 如果所要登录的用户名password为空, 可以忽略此选项。
  • 查看数据库

    语法:

    show databases;
    
  • 创建数据库

    语法:

    create database 库名;
    

    这里创建一个名字为lianjia的库名。

  • 创建数据表,下面命令,可以在console窗口Mysql提示符下录入,也可以在idle的sql控制台下录入,都可以。 语法:

    create table lianjia_cs
    (
    	id  int auto_increment,
        title     varchar(100) null,
        position  varchar(200) null,
        houseInfo varchar(200) null,
        priceInfo varchar(50)  null,
        unitPrice varchar(50)  null,
       	primary key(id)
    )DEFAULT CHARSET=utf8;
    

    关于爬虫中几个常用库的使用方法总结

3.5.3 数据库与idle的连接操作

  • 用VSCode连接MySQL8.0,步骤如下: (1)点扩展插件,输入MySQL,安装第一个,如图。 关于爬虫中几个常用库的使用方法总结 (2)打开左侧资源管理器,点+号,分别录入host、user、password、port,最后一个回车即可,我这里对应的是localhost、root、root、3306。然后就轻松建立一个localhost连接了。 关于爬虫中几个常用库的使用方法总结 注意:如果连接不成功,下面有Error提示的话,一般要更新一下password,才能连接。命令如下: alter user ‘root’@‘localhost’ identified with mysql_native_password by ‘root’;
  • 用PyCharm连接数据库的方法,相对也很简单。 (1)单击右侧数据库,再点+号,再点MySQL即可建立。 关于爬虫中几个常用库的使用方法总结 (2)在弹出的对话框中,输入相应的参数。

关于爬虫中几个常用库的使用方法总结

3.5.4 程序全部代码

# -*- coding:utf-8 -*-
"""
    # @Time:2022/12/19 0019 13:53
    # @Author:晚秋拾叶
    # @File:链家长沙房源.py
    # @PyCharm之Python
    # 完成“标题,位置,户型,总价,单价”几个信息的收集并保存
"""
import requests
import pymysql
from pyquery import PyQuery as pq


class LianJian_changsha(object):
    def __init__(self, num):
        self.url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(num)
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54',

        }
        # 创建数据库连接
        self.db = pymysql.Connect(
            host="localhost",
            port=3306,
            user="root",
            password="root",
            db="lianjia"
        )
        # 再创建数据库游标
        self.cursor = self.db.cursor()

    ''' 1. 发起请求并获取数据 '''

    def get_data_index(self):
        # 可以使用urlli库里的方法from urllib.request import Request
        # 即用urllib中的request模块里的Request类定义解析的网页数据,
        # 不过需要用read()读取二进制内容,再用decode('utf-8')转为Unicode编码
        # 所以不如requests库来得方便
        """ (1)用到第一个库requests的get方法,获取总的网页源代码 """
        resp = requests.get(self.url, headers=self.headers)
        resp.encoding = 'utf-8'
        if resp.status_code == 200:
            return resp.text
        else:
            return None

    ''' 2. 把得到的网页文本信息进行解析 '''

    def parse_data_index(self, resp):
        # 进一步筛选想要的源代码内容,缩小范围
        """ (2)还是用xpath定位好范围 """
        doc = pq(resp)
        sellListContent = doc(".sellListContent li")
        for data in sellListContent.items():
            # 下面用了CSS选择器,加上text方法获取文本内容
            title = data(".info.clear .title a").text()
            position = data(".info.clear .flood").text()
            houseInfo = data(".info.clear .houseInfo").text()
            priceInfo = data(".info.clear .totalPrice.totalPrice2 span").text() + "万元"
            unitPrice = data(".info.clear .unitPrice span").text()
            # 定义sql语句,以便下面执行插入操作
            sql = "insert into lianjia_cs (title,position,houseInfo,priceInfo,unitPrice) values(%s,%s,%s,%s,%s);"
            # 把信息字段写入参数
            params = [(title, position, houseInfo, priceInfo, unitPrice)]
            # 执行语句
            self.cursor.executemany(sql, params)
            # 提交数据库
            self.db.commit()

    """ 3. 把上面方法整合起来完成业务逻辑"""

    def run(self):
        resp = self.get_data_index()  # 获取网页信息
        self.parse_data_index(resp)


if __name__ == '__main__':
    # 爬取前5页的数据
    for n in range(1, 6):
        spider = LianJian_changsha(n)
        spider.run()

  • 结果如图。

关于爬虫中几个常用库的使用方法总结

3.6 parsel方法

  • 这次用parsel方法,把这个任务完成。这个方法,其实很简单,提取到网页源代码后,还是应用了xpath方法。不过这次数据,我再用MongoDB数据库保存。

3.6.1 安装MongoDB

  • 安装包下载地址:https://www.mongodb.com/try/download/community 关于爬虫中几个常用库的使用方法总结

  • step1:打开安装包直接点击Next 关于爬虫中几个常用库的使用方法总结

  • step2:继续点击Next 关于爬虫中几个常用库的使用方法总结

  • step3:点击自定义安装 关于爬虫中几个常用库的使用方法总结

  • step4:选择好安装路径,点击Next 关于爬虫中几个常用库的使用方法总结

  • step5:点击Next 关于爬虫中几个常用库的使用方法总结

  • step6:取消可视化界面勾线,直接点击Next安装 关于爬虫中几个常用库的使用方法总结

3.6.2 初始化MongoDB

  • step1:配置环境变量,找到MongoDB安装路径下的bin目录 关于爬虫中几个常用库的使用方法总结

  • step2:计算机--右击--属性--高级系统设置--环境变量--系统变量--path--新建,将bin目录复制进去即可 关于爬虫中几个常用库的使用方法总结 补充:进到data目录里面,新建两个文件夹,一个是db,一个是log

  • step3:打开cmd,输入mongod -dbpath "F:\MongoDB\data\db" -logpath "F:\MongoDB\data\log\mongo.log" 关于爬虫中几个常用库的使用方法总结

  • step4:重新打开一个cmd窗口,输入mongo来启动MongoDB shell 端 这里遇到一个问题就是,我安装的是高版本的MongoDB,显示mongo命令不存在。 关于爬虫中几个常用库的使用方法总结 查了一番资料,才明白,高版本已经没有这个命令了。然后根据资料提示,重新下载一个mongosh文件代替。 地址:https://www.mongodb.com/try/download/shell 关于爬虫中几个常用库的使用方法总结

  • 下载解压后,找到bin目录,把这两个文件,复制粘贴到MongoDB下的bin目录。 关于爬虫中几个常用库的使用方法总结关于爬虫中几个常用库的使用方法总结

  • 再执行mongosh命令就行了。 关于爬虫中几个常用库的使用方法总结

  • **step5: 创建一个数据库,再建立一个集合 ** 创建\删除数据库

    use db_lianjia
    # 如果数据库不存在,则创建数据库,否则切换到指定数据库。
    
    db.dropDatabase()
    # 删除数据库之前,先进入数据库,之后执行
    # 删除当前数据库
    

    实例:

    >use db_lianjia
    switched to db db_lianjia
    >db
    db_lianjia
    

    如果你想查看所有数据库,可以使用 show dbs 命令:

    > show dbs
    admin   0.000GB
    config  0.000GB
    local   0.000GB
    

    可以看到,我们刚创建的数据库 db_lianjia并不在数据库的列表中, 要显示它,我们需要向 db_lianjia 数据库插入一些数据。

    增删改查操作

    MongoDB中的一张表被称为一个集合

    插入数据

    • 语法:
    # db.集合名.insert({})  数据格式为json
    db.demo.insert({name:"坤哥"})
    # { "_id" : ObjectId("63465fb77811f81334940270"), "name" : "坤哥" }
    

    上面的命令执行完,就自动创建了一个demo表。总结上面的命令如下图: 关于爬虫中几个常用库的使用方法总结

    • 我后面接着连接数据库,进行一个集合的实例,进一步理解上面的操作。

3.6.3 数据库与IDLE的连接操作

  • 连接MongoDB时,需要使用PyMongo库里面的MongoClient方法,格式如下:
    import pymongo
    client = pymongo.MongoClient(host='localhost', port=27017)
    
  • 上面语法用来创建MongoDB的连接对象。
  • (1)PyCharm下安装MongoDB插件。
    • 点击右侧的数据库,一步步点击 关于爬虫中几个常用库的使用方法总结

    • 下一步,输入名称:MongoDB,主机:localhost,再点击下方的“下载”,最后完成测试连接。

      关于爬虫中几个常用库的使用方法总结注意:这里反复下载提示重试,最后发现,需要github账号。

    • 终于下载并连接成功了。 关于爬虫中几个常用库的使用方法总结

  • (2)再用VSCode连接一下。
    • 点扩展,再搜索mongo,如图下载MongoDB for VS Code: 关于爬虫中几个常用库的使用方法总结

    • 再点左侧出现的数据库,然后点CONNECTIONS右侧的+号。 关于爬虫中几个常用库的使用方法总结

    • 出现New connection之后,输入localhost,再输入账号、pwd以及本地数据库的名称。 关于爬虫中几个常用库的使用方法总结

  • 提示,账号密码的设置在管理员console命令中,分如下几步完成。
    • mongosh   # 打开MongoDB;
    • use db_lianjia   # 创建或打开数据库;
    • db.createUser({user: "root", pwd: "root", roles: [{role: "root", db: "admin"}]})   # 修改用户和密码 关于爬虫中几个常用库的使用方法总结
    • 最后也完成VSCode下的MongoDB的连接。 关于爬虫中几个常用库的使用方法总结

3.6.4 程序全部代码

# -*- coding:utf-8 -*-
"""
    # @Time:2022/12/19 0019 13:53
    # @Author:晚秋拾叶
    # @File:链家长沙房源.py
    # @PyCharm之Python
    # 完成“标题,位置,户型,总价,单价”几个信息的收集并保存
"""
import requests
import pymongo
from parsel import Selector


class LianJian_changsha(object):
    def __init__(self, num):
        self.url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(num)
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54',
        }
        # 创建数据库连接
        self.client = pymongo.MongoClient(host="localhost", port=27017)
        # 再创建一个数据库,下面命令执行的时候,是没有创建,有则连
        self.db = self.client["db_lianjia"]

    ''' 1. 发起请求并获取数据 '''

    def get_data_index(self):
        # 可以使用urlli库里的方法from urllib.request import Request
        # 即用urllib中的request模块里的Request类定义解析的网页数据,
        # 不过需要用read()读取二进制内容,再用decode('utf-8')转为Unicode编码
        # 所以不如requests库来得方便
        """ (1)用到第一个库requests的get方法,获取总的网页源代码 """
        resp = requests.get(self.url, headers=self.headers)
        resp.encoding = 'utf-8'
        if resp.status_code == 200:
            return resp.text
        else:
            return None

    ''' 2. 把得到的网页文本信息进行解析 '''

    def parse_data_index(self, resp):
        # 进一步筛选想要的源代码内容,缩小范围
        """ 
        (2)如同前面章节提到的,SelectorList对象再用CSS选择器选择的属性,
            先是被转成了xpath,所以这里还是用xpath定位匹配文本 
        """
        # 创建一个Selector对象
        st = Selector(resp)
        # 创建一个SelectorList对象
        sellListContent = st.css(".sellListContent li")
        i = 0
        for data in sellListContent:
            title = data.xpath('.//div[@class="title"]/a/text()').get()
            position = ",".join(data.xpath('./div[1]/div[2]//a/text()').getall())
            houseInfo = data.xpath('.//div[@class="houseInfo"]/text()').get()
            priceInfo = data.xpath('.//div[contains(@class,"totalPrice")]/span/text()').get() + "万元"
            unitPrice = data.xpath('.//div[@class="unitPrice"]/span/text()').get()

            yield {'标题': title, '位置': position, '户型': houseInfo, '总价': priceInfo, '单价': unitPrice}
           

    """ 3. 把上面方法整合起来完成业务逻辑"""

    def run(self):
        resp = self.get_data_index()  # 获取网页信息
        parse_data = self.parse_data_index(resp)
        for item in parse_data:
            print(item)
            self.db.lianjia_cs.insert_one(item)


if __name__ == '__main__':
    # 爬取前5页的数据
    for n in range(1, 6):
        spider = LianJian_changsha(n)
        spider.run()

关于爬虫中几个常用库的使用方法总结

  • 用db命令也能查看数据已经写入。 关于爬虫中几个常用库的使用方法总结

4. 面向对象的写法总结

  • 面向对象的编程,能够让你的思路条理化。上面几种爬虫库完成既定目标,都是基于这个思想。
  • 首先,都是建立一个类,包含要抓取的网页的地址,伪装和各种数据库的连接等等。
  • 再写几个重要的方法。分别是获取网页数据、用各种爬虫库里的方法对网页数据进行解析、写入各种形式的保存方式的类方法、整合运行的类方法、调用类的主程序。。。

4.1 获取网页数据

  • 这部分代码,所有的爬虫库都用到requests里的get方法,不过,遇到大型数据的爬取,就有点力不从心了。好在后面还会学到更强大的处理方法。
  • 这里不管是得到的是什么数据,都要保证返回不为空,否则后面的工作也就成空了。

4.2 网页数据解析提取

  • 这个题目中的要求,基本没有字典形式的数据,也没有抓取图像和音视频的情况,如果有的话,自然用xpath和bs4更方便一些。

4.3 遍历源代码数据列表

  • 这个题目中,网页数据解析的时候,只是缩小范围,再得到列表,用遍历的for语句,结合各种方法得到一条一条的数据了。至于什么时候用return返回数据,还是用yield生成器,则要看保存的形式和地方了。

4.4 数据保存的问题解决

  • 保存的方式,从简单的控制台打印,到文本文档,csv格式,再到稍复杂的csv和excel格式,一直到两种数据库MySQL和MongoDB的形式,一遍一遍改写和测试,加上我这新手不熟悉不断的找寻各种问题解决的资料信息,一共花费了近4天的时间,终于完成这部分知识的笔记。

4.5 业务逻辑的实现

  • 再总结一个问题,就是业务逻辑的实现。主要是在run方法里面完成,翻页的效果,除了bs4这个方法结果保存为excel表格要处理翻页,其它的都在main主函数里面for循环完成。
  • bs4这段中,为了追加成功,把这个功能写到了解析的类方法parse_data()里面,然后少了写的方法write_data()了。

4. 总结

  • 上面写得太多,不总结了。总结一句,就是学习的过程,如柳暗花明,如众里寻他,如漫漫轻云,又如南朝四百八十寺,更如春风又绿江南岸。