Python开发简单爬虫速成教程


一、简介

按照一定的规则,自动抓取网络信息的程序或者脚本,搜索引擎的重要组成。

  • 搜索引擎
  • 数据分析
  • 人工智能
  • 薅羊毛、抢车票

爬虫产品:

神箭手、八爪鱼、造数、后羿采集器

数据储备:

  • python编程基础
  • http
  • 数据库

怎么学:

  • python语法知识
  • python爬虫常用到的几个重要内置库Requests,用于请求网页
  • 学习正则表达式re、Xpath(IxmI)等网页解析工具
  • 开始一些简单的网站爬取,了解爬取数据的过程(当当网图书数据)
  • 与数据库结合,将爬取数据进行存储

安装MongoDB数据库

  • 介于关系型数据库和非关系型数据库之间的产品
  • 本质是非关系型数据库,最像关系数据库
  • 支持的数据结构非常松散,类似json的bson格式
  • 可以存储比较复杂的数据

非关系模型:

  • 列模型,一列为一个记录,分布式数据库,HBase
  • 键值对,redis
  • 文档类,类似键值对,Mongodb

效率非常高,存储在内存中,断电即失,现在也可存储到磁盘中

检查安装是否成功:

mongodb 怎么存储对象_xml

修改设置:

/bin/mongod.cfg

mongodb 怎么存储对象_html_02

右击我的电脑,管理,服务和应用程序,服务,找到MongoDB,点击重新启动。同一个局域网的机器可以连接。

安装Navicat:支持多种数据库的连接

安装教程:Navicat安装教程

使用教程:在 Navicat for MongoDB 使用文档

使用Navicat,进行MongoDB数据库的连接:

注意主机和端口号的设置

二、request模块入门

requests库:

通过Requests库发送http请求:

mongodb 怎么存储对象_html_03

Requests模块的安装:

cmd直接安装:pip install requests

Requests模块支持的http方法:

  • Get方法:请求资源
  • Post方法:向服务端发送信息和数据,表单提交
  • Head方法:请求资源的一些信息而不是全部信息,用于确认URL的有效性以及资源更新的日期时间
  • Put方法:上传文档
  • Connection方法:客户端想要确定一个明确的连接到远程主机,便于通过Http代理服务器进行SSL加密通信时连接使用,在抓包时使用

【重点】通过requests模块发送get请求

import requests
r=requests.get('http://httpbin.org/ip') #会返回当前主机的一个外网地址
# r1=requests.get('https://www.imooc.com') 
print(r.text) # 输出请求体

cmd查看内网ip:ipconfig

百度查看ip地址:ip地址

【重点】通过requests模块发送post请求

一般出现在html的form表单里面

import requests

r2=requests.post(url='http://httpbin.org/post',data={'name':'imooc'})
print(r2.text)

通过requests模块的get请求构造url

主要用在get请求里面

mongodb 怎么存储对象_xml_04

data={"key1":"value1","key2":"value2"}
response=requests.get("http://httpbin.org/get",params=data)
# 查看当前请求的url
print(response.url)

查看响应的返回头和返回体

# 查看响应的返回头
print(response.headers)
# 查看响应的返回体
print(response.text)

返回头:

mongodb 怎么存储对象_mongodb 怎么存储对象_05

【重点】请求图片

url='https://www.imooc.com/static/img/index/logo2020.png'
r1=requests.get(url)
# 访问图片返回的是二进制数据,需要用content查看输出
print(r1.content) 

#写入图片数据
with open("imooc.png","wb") as f:
    f.write(r1.content)

图片二进制数据:

mongodb 怎么存储对象_python_06

写入图片:

mongodb 怎么存储对象_html_07

查看响应的json数据

r1=requests.get(url="http://httpbin.org/ip")
print(r1.json()) # 整个json对象 {'origin': '124.160.215.146'}

print(r1.json()["origin"]) # json中某一项 124.160.215.146

查看响应状态码

print(r1.status_code)

查看request的请求头

print(r1.request.headers)

mongodb 怎么存储对象_爬虫_08

请求头可以修改,可以通过构造request请求头

headers={
    "user-agent":"joseph/v1"
}
r1=requests.get(url="http://httpbin.org/ip",headers=headers)
print(r1.request.headers)

mongodb 怎么存储对象_xml_09

在反爬机制中可以使用,可以模拟win,ipad,手机

三、requests模块进阶

设置连接超时

当请求超时,放弃请求

# 0.0001秒之内返回网页数据
# 超时时间一般设置为2到3秒
start_time=time.time()
r1=requests.get(url="https://www.imooc.com",timeout=2)
end_time=time.time()

print(r1.text)
print(end_time-start_time)

查看响应设置的cookies

可以在headers中查看

也可以通过cookies查看

行为和字典非常的像

r1=requests.get(url="https://www.baidu.com")
print(r1.headers)
print(r1.cookies)
print(r1.cookies["BDORZ"])

mongodb 怎么存储对象_爬虫_10

在请求中携带cookies

cookies={
    "username":"joseph"
}
r1=requests.get(url="http://httpbin.org/cookies",cookies=cookies)
print(r1.cookies) # 输出响应设置的cookies
print(r1.text) # 请求url在响应中返回请求的cookies

mongodb 怎么存储对象_xml_11

证书校验,SSLError问题

request可以为HTTPS请求验证SSL证书,就像web浏览器一样

SSL验证默认是开启的,如果证书验证失败,requests会抛出SSLError

# 关闭SSL校验
r1=requests.get(url="https://www.baina.org",verify=False)
# 方法二:指定网站的SSL证书,但是一般没有
print(r1.text)

异常

  • 网络问题:如DNS查询失败,拒绝连接,会抛出ConnectionError异常
  • Http请求返回了不成功的状态码:HTTPError异常
  • 请求超时:Timeout异常
  • 请求次数超过了设定的最大重定向次数,TooManyRedirects异常
  • 所有request显式抛出的异常都继承自requests.exceptions.RequestException

【重点】保持登录凭据,requests.session(),爬取需登录的网站+定制请求头

http://account.chinaunix.net/login进行登录验证

1.通过get请求访问登录页面,这个时候还没有填写username和password

mongodb 怎么存储对象_爬虫_12

mongodb 怎么存储对象_xml_13

mongodb 怎么存储对象_python_14

2.post请求访问登录

第二个使用的token信息就是第一个请求setCookies设置的

时间戳,删除后3位

mongodb 怎么存储对象_爬虫_15

mongodb 怎么存储对象_mongodb 怎么存储对象_16

mongodb 怎么存储对象_python_17

mongodb 怎么存储对象_xml_18

3.index页面

cookies携带了很多数据,

可以通过定制请求头和设置请求的cookies 进入index页面,可行但太麻烦。

mongodb 怎么存储对象_mongodb 怎么存储对象_19

mongodb 怎么存储对象_mongodb 怎么存储对象_20

mongodb 怎么存储对象_python_21

保持登录凭据,从而直接绕过登录,直接进入到index页面:

  • get请求拿token信息
  • post请求提交用户名密码
  • 第三个请求直接访问登录后index页面
定制请求头header

请求头替换添加引号:

采用正则表达式

mongodb 怎么存储对象_html_22

代码实现,利用requests.session()保存登录凭据
# request.session,创建一个保持登录凭据的session实例
login_session=requests.session()


# 1、get请求,获取token信息
token_url="http://account.chinaunix.net/login?"
headers={
    "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding":"gzip, deflate",
    "Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "Cache-Control":"no-cache",
    "Host":"account.chinaunix.net",
    "Pragma":"no-cache",
    "Proxy-Connection":"keep-alive",
    "Upgrade-Insecure-Requests":"1",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36 Edg/91.0.864.71"
}
# 发送第一个get请求
token_response=login_session.get(url=token_url,headers=headers)
# print(token_response.headers.get("Set-Cookie"))
# 通过正则表达式拿到token值,需要导入import re
token_search=re.compile(r"XSRF-TOKEN=(.*?);")
token_value=token_search.search(token_response.headers.get("Set-Cookie"))
print(token_value.group(1))



# 2.post请求
# 时间戳导入 import time模块生成
login_url="http://account.chinaunix.net/login/login"
data={
    "username": "dazhuang_imooc",
    "password": "abcd1234",
    "_token": "QPABdRUD0iujCY7GCgv4RARvOlUBcQY39e3vSaxu",
    "_t": int(time.time())
}
# 发送post请求,提交用户名和密码,注意不要忘记携带data
login_response=login_session.post(url=login_url,headers=headers,data=data)
print(login_response.text)



# 3.访问index页面
index_url="http://account.chinaunix.net/ucenter/user/index"
# 【重要】一定要使用login_session,否则登录凭据是不携带的
index_response=login_session.get(url=index_url)
print(index_response.text)

【重点】设置代理,隐藏请求

服务端可以看到客户端的请求地址,我们可以通过设置代理来隐藏我们自己

快代理:

  • 可以提供隧道代理
  • 本机连接代理的两种形式:每个请求携带用户名和密码,设置白名单类似ssh
# 查看本机的ip和城市
url="http://pv.sohu.com/cityjson"
response=requests.get(url=url)
print(response.text)
# 1.挑选代理厂商:阿布云,芝麻代理,快代理
# 2.把代理信息设置到代码中,两种格式:http和https
url="http://pv.sohu.com/cityjson"

# 免费代理,无需用户名和密码
proxies1={
    "http":"http://117.157.197.18:3128",
    "https":"https://117.157.197.18:3128",
}

# 付费代理:格式需要注意,定义一个字典http和https
# 用户名:密码@代理的接口:端口号
proxies={
    "http":"http://t10422119804320:oynsb8dh@tps194.kdlapi.com:15818",
    "https":"https://t10422119804320:oynsb8dh@tps194.kdlapi.com:15818",
}

# 发送请求携带代理信息
for i in range(5):
    response=requests.get(url=url,proxies=proxies)
    print(response.text)

四、Xpath基础和lxml模块

XPath知识点

html节点与节点间的关系,Xpath和lxml获取想要的数据字段

节点有哪些?


mongodb 怎么存储对象_爬虫_23

先辈节点不唯一,后辈节点也不唯一


mongodb 怎么存储对象_mongodb 怎么存储对象_24

学习XPath需要安装插件:XPath helper

mongodb 怎么存储对象_xml_25

xpath路径表达式:

汪曾祺《黄油烙饼》

/div 单斜杆定位根节点下div节点

//div 双斜杠定位文档中所有div节点

//div[@class='pic_art'] 获取特定元素 网页元素

//div[@class='pic_art']/text() 获取特定元素 整个文本信息

//div[@class='pic_art']/. 一个点表示当前节点

//div[@class='pic_art']/.. 两个点表示获取当前节点的父节点

/div/a 从根节点开始选取div节点下的a节点

//div[@class='info']/span[@class='time']

/div/a[2]/img 从根节点开始选取div节点下的第二个a节点下的img节点

//div[@class=‘header-wrapper’] 选取所有属性class的值为header-wrapper的div节点

  • 在节点后加上带有数字的方括号,兄弟节点索引/div/a[2]/img
  • 在节点后加上属性名-值对的方括号,可以筛选出需要的节点//div[@class='info']/span[@class='time']
  • //* 选取所有元素
  • //@* 选取所有带属性的元素

xpath函数:

div/p/text() 选取文本内容

模糊查询:

//div[contains(@class,”post”)] 选取带有class属性且包含“post”的所有div节点。取反//div[ not(contains(@class,”post”))]

/div/p[last()-1] 选取div下倒数第二个p节点

div/p[position()>1] 选取div下第二个p节点后的所有兄弟节点

/div/a|div/p 选取div下的a节点和div下的p节点,竖线分隔or

Python lxml模块

可以灵活处理xml

支持xpath

利用XPath语法,快速定位特定元素以及节点信息,以提取出html或xml目标数据

安装lxml库:

在cmd中输入pip install lxml

实操:通过xpath获取想要的数据字段

from lxml import etree
# 不包含html标签和body标签
data="""
<div>
    <ul>
        <li class="item-0"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a></li>
    </ul>
</div>
"""
#html实例化,添加了html和body标签
html=etree.HTML(data) 
print(etree.tostring(html).decode()) 


print(html.xpath("//li"))
print(html.xpath("//li/@class"))

print(html.xpath("//li/a[@href='link1.html']"))
print(html.xpath("//li[1]/a[1]"))
print(html.xpath("//li[last()]/a[1]"))

print(html.xpath("//li/a/span"))
print(html.xpath("//li//span")) 
# 输出的所有结果都是列表的形式

五、实战:当当网5星图书排行榜数据抓取

目标站点

当当5星图书排行榜

抓取5星好评图书数据:


mongodb 怎么存储对象_xml_26

items=//ul[@class='bang_list clearfix bang_list_mode']/li #所有图书条目,返回列表

for item in items:
    item.xpath(".//div[@class='name']/a/text()") #图书的标题
    item.xpath(".//div[@class='star']/a/text()") #图书的评论
    item.xpath(".//span[@class='tuijian']/text()") #图书的推荐信息
    item.xpath(".//div[@class='publisher_info'][1]/a/@title") #图书的作者
    item.xpath(".//div[@class='publisher_info'][2]/span/text()") #图书的出版时间
    
    item.xpath(".//div[@class='publisher_info'][2]/a/text()") #出版社信息
    item.xpath(".//div[@class='biaosheng']/span/text()") #评分信息
    item.xpath(".//div[@class='price']/p[1]/span[1]/text()") #图书价格
    item.xpath(".//div[@class='price']/p/span[@class='price_s']/text()") #折扣信息
    item.xpath(".//div[@class='price']/p[@class='price_e']/span/text()") #电子书价格

构造请求头headers:浏览器复制请求头,利用notepad++正则表达式格式化,加引号

【易错】需要去除复制的header里面的空格

mongodb 怎么存储对象_html_27

爬取图书数据,存储为列表形式

import requests
from lxml import etree

class Dangdang(object):
    def __init__(self):
        """构造方法"""
        self.header={
            "Host":"bang.dangdang.com",
            "Proxy-Connection":"keep-alive",
            "Pragma":"no-cache",
            "Cache-Control":"no-cache",
            "Upgrade-Insecure-Requests":"1",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36 Edg/91.0.864.71",
            "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "Accept-Encoding":"gzip, deflate",
            "Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
        }

        
    def get_dangdang(self,page):
        """发送请求到当当网获取数据"""
        url="http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-%s" % page
        # 发送请求
        response=requests.get(url=url,headers=self.header) # 1.response获取一个页面的网页内容
        if response:
            # 2.HTML数据的实例化。通过xpath表达式抽取网页数据,获取各个图书的网页数据,以列表形式返回
            html=etree.HTML(response.text)
            items=html.xpath("//ul[@class='bang_list clearfix bang_list_mode']/li")
            return items

        
    # xpath获取的数据是一个列表,转换为字符串
    def join_list(self,item):
        """处理列表到字符串"""
        return "".join(item)

    
    def parse_item(self,items):
        """解析具体的图书条目"""
        # 定义一个列表,用于存放存储到MongoDB之前的数据
        result_list=[]
		
        # 1.对抽取的每一个图书网页数据,进行进一步数据抽取,获得每本图书的各项具体信息节点
        for item in items: 
            title=item.xpath(".//div[@class='name']/a/text()") #图书的标题
            comment=item.xpath(".//div[@class='star']/a/text()") #图书的评论
            recommend=item.xpath(".//span[@class='tuijian']/text()") #图书的推荐信息
            author=item.xpath(".//div[@class='publisher_info'][1]/a/@title") #图书的作者
            publication_time=item.xpath(".//div[@class='publisher_info'][2]/span/text()") #图书的出版时间            
            press=item.xpath(".//div[@class='publisher_info'][2]/a/text()") #出版社信息
            score=item.xpath(".//div[@class='biaosheng']/span/text()") #评分信息
            price=item.xpath(".//div[@class='price']/p[1]/span[1]/text()") #图书价格
            discount=item.xpath(".//div[@class='price']/p/span[@class='price_s']/text()") #折扣信息
            e_book=item.xpath(".//div[@class='price']/p[@class='price_e']/span/text()") #电子书价格 
			
            # 2.每本图书的各项具体信息都是以列表存储节点的形式展现,将列表变为字符串。再将每个节点信息封装成一个JSON对象,存储到结果列表result_list中
            result_list.append(
                {
                    "title":self.join_list(title),
                    "comment":self.join_list(comment),
                    "recommend":self.join_list(recommend),
                    "author":self.join_list(author),
                    "publication_time":self.join_list(publication_time),
                    "press":self.join_list(press),
                    "score":self.join_list(score),
                    "price":self.join_list(price),
                    "discount":self.join_list(discount),
                    "e_book":self.join_list(e_book)
                }
        )
        return result_list

    

def main():
    import json
    d=Dangdang()
    for page in range(1,26):
        items=d.get_dangdang(page=page)
        result=d.parse_item(items=items)
        print(json.dumps(result)) #复制一条,浏览器打开json.cn可以看到json形式
        
        
        
if __name__ == '__main__':
    main()

mongodb 怎么存储对象_python_28

python操作MongoDB

安装pymongo:

pip install pymongo

python中连接mongodb数据库+插入数据

import pymongo

# 指定一个客户端连接Mongodb
pymongo_client=pymongo.MongoClient("mongodb://127.0.0.1:27017")
# 指定数据库的名称imooc
# 只有库里面由内容插入的时候,才会创建数据库
pymongbo_db=pymongo_client["imooc"]
# 创建集合(数据库表)
pymongo_collection=pymongbo_db["pymongo_test"]
data={
    "name":"imooc",
    "flag":1,
    "url":"https://www.baidu.com"
}
# 插入一条数据
pymongo_collection.insert_one(data)

# 插入多条数据,列表
mylist=[
    {"name":"taobao","flag":"100","url":"https://www.taobao.com"},
    {"name":"QQ","flag":"101","url":"https://www.qq.com"},
    {"name":"facebook","flag":"102","url":"https://www.facebook.com"},
    {"name":"zhihu","flag":"103","url":"https://www.zhihu.com"},
    {"name":"github","flag":"104","url":"https://www.github.com"},
]
pymongo_collection.insert_many(mylist)

mongodb 怎么存储对象_爬虫_29

数据查询:

# 查询
# 第一个{}表示进行数据的查询,第二个{}进行过滤,find是查询所有数据
result=pymongo_collection.find({},{"_id":0,"name":1,"flag":1}) #结果是一个游标<pymongo.cursor.Cursor object at 0x00000201BE84EEB0>,可以通过for循环进行遍历
for item in result:
    print(item)

# 查询一条数据
result2=pymongo_collection.find_one() 
print(result2)

# 高级查询
# result3=pymongo_collection.find({"flag":{"$gt":"100"}}) # 查询结果flag都大于100,大小输出
result3=pymongo_collection.find({"name":{"$regex":"^g"}}) # 正则表达式,限定输出
for item in result3:
    print(item)

mongodb 怎么存储对象_html_30

数据更新:

# 数据更新
# 更新一条(第一个参数是查询条件,第二个参数是要修改成为什么样子)
pymongo_collection.update_one({"name":{"$regex":"^g"}},{"$set":{"name":"gitee"}})

result=pymongo_collection.find({},{"_id":0,"name":1,"flag":1}) 
for item in result:
    print(item)

# 更新多条
pymongo_collection.update_many({},{"$set":{"name":"gitee"}})

result=pymongo_collection.find({},{"_id":0,"name":1,"flag":1})
for item in result:
    print(item)

数据删除:

# 数据删除
# 删除一条
pymongo_collection.delete_one({"url":"https://www.baidu.com"})
# 删除所有数据
pymongo_collection.delete_many({})

将爬取的当当网图书数据存储到mongdb中

from typing import Collection
from pymongo import collection, mongo_client
import requests
from lxml import etree
import pymongo
from pymongo.collection import Collection # Collection不要写错

class Dangdang(object):
    # ******************************************************************************************
    # 连接数据库
    mongo_client=pymongo.MongoClient(host="127.0.0.1",port=27017)
    # 指定数据库为dangdang_db
    dangdang_db=mongo_client["dangdang_db"]
    # ******************************************************************************************

    def __init__(self):
        self.header={
            "Host":"bang.dangdang.com",
            "Proxy-Connection":"keep-alive",
            "Pragma":"no-cache",
            "Cache-Control":"no-cache",
            "Upgrade-Insecure-Requests":"1",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36 Edg/91.0.864.71",
            "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "Accept-Encoding":"gzip, deflate",
            "Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
        }
        # ******************************************************************************************
        # 构造方法创建Collection
        self.dangdang=Collection(Dangdang.dangdang_db,"dangdang") # 表名为dangdang
        # ******************************************************************************************

    def get_dangdang(self,page):
        """发送请求到当当网获取数据"""
        url="http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-%s" % page
        print(url)
        # 发送请求
        response=requests.get(url=url,headers=self.header)
        if response:
            # HTML数据的实例化
            html=etree.HTML(response.text)
            items=html.xpath("//ul[@class='bang_list clearfix bang_list_mode']/li")
            return items

    # xpath获取的数据是一个列表,转换为字符串
    def join_list(self,item):
        """处理列表到字符串"""
        return "".join(item)

    def parse_item(self,items):
        """解析具体的图书条目"""
        # 定义一个列表,用于存放存储到MongoDB之前的数据的
        result_list=[]

        for item in items: # 一个items包括25条数目,即最终一个result_list包含25条数据每次
            title=item.xpath(".//div[@class='name']/a/text()") #图书的标题
            comment=item.xpath(".//div[@class='star']/a/text()") #图书的评论
            recommend=item.xpath(".//span[@class='tuijian']/text()") #图书的推荐信息
            author=item.xpath(".//div[@class='publisher_info'][1]/a/@title") #图书的作者
            publication_time=item.xpath(".//div[@class='publisher_info'][2]/span/text()") #图书的出版时间            
            press=item.xpath(".//div[@class='publisher_info'][2]/a/text()") #出版社信息
            score=item.xpath(".//div[@class='biaosheng']/span/text()") #评分信息
            price=item.xpath(".//div[@class='price']/p[1]/span[1]/text()") #图书价格
            discount=item.xpath(".//div[@class='price']/p/span[@class='price_s']/text()") #折扣信息
            e_book=item.xpath(".//div[@class='price']/p[@class='price_e']/span/text()") #电子书价格 

            result_list.append(
                {
                    "title":self.join_list(title),
                    "comment":self.join_list(comment),
                    "recommend":self.join_list(recommend),
                    "author":self.join_list(author),
                    "publication_time":self.join_list(publication_time),
                    "press":self.join_list(press),
                    "score":self.join_list(score),
                    "price":self.join_list(price),
                    "discount":self.join_list(discount),
                    "e_book":self.join_list(e_book)
                }
            )

        return result_list
	
    # ******************************************************************************************
    def insert_data(self,result_list):
        """插入数据到mongodb"""
        self.dangdang.insert_many(result_list) #一次20条数目
    # ******************************************************************************************

def main():
    import json
    d=Dangdang()
    for page in range(1,26):
        items=d.get_dangdang(page=page)
        result=d.parse_item(items=items)
        # print(len(result)) # 浏览器每个页面输出记录条数
        # print(json.dumps(result)) #复制一条,浏览器打开json.cn可以看到json形式
        d.insert_data(result_list=result)        


if __name__ == '__main__':
    main()

爬虫的伪装:使用代理

from typing import Collection
from pymongo import collection, mongo_client
import requests
from lxml import etree
import pymongo
from pymongo.collection import Collection

class Dangdang(object):
    # 连接数据库
    mongo_client=pymongo.MongoClient(host="127.0.0.1",port=27017)
    # 指定数据库为dangdang_db
    dangdang_db=mongo_client["dangdang_db"]

    def __init__(self):
        self.header={
            "Host":"bang.dangdang.com",
            "Proxy-Connection":"keep-alive",
            "Pragma":"no-cache",
            "Cache-Control":"no-cache",
            "Upgrade-Insecure-Requests":"1",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36 Edg/91.0.864.71",
            "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "Accept-Encoding":"gzip, deflate",
            "Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
        }
        # 构造方法创建Collection
        self.dangdang=Collection(Dangdang.dangdang_db,"dangdang") # 表名为dangdang
        
        # ******************************************************************************************
        #使用代理,在request方法中加上代理信息
        self.proxies={
            "http":"http://t10422119804320:oynsb8dh@tps194.kdlapi.com:15818",
            "https":"https://t10422119804320:oynsb8dh@tps194.kdlapi.com:15818",
        }
        # ******************************************************************************************


    def get_dangdang(self,page):
        """发送请求到当当网获取数据"""
        url="http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-%s" % page
        print(url)
        # ******************************************************************************************
        # 发送请求,此时爬虫项目使用了代理,进行爬取数据的
        response=requests.get(url=url,headers=self.header,proxies=self.proxies)
        # ******************************************************************************************
        if response:
            # HTML数据的实例化
            html=etree.HTML(response.text)
            items=html.xpath("//ul[@class='bang_list clearfix bang_list_mode']/li")
            return items

    # xpath获取的数据是一个列表,转换为字符串
    def join_list(self,item):
        """处理列表到字符串"""
        return "".join(item)

    def parse_item(self,items):
        """解析具体的图书条目"""
        # 定义一个列表,用于存放存储到MongoDB之前的数据的
        result_list=[]

        for item in items: # 一个items包括25条数目,即最终一个result_list包含25条数据每次
            title=item.xpath(".//div[@class='name']/a/text()") #图书的标题
            comment=item.xpath(".//div[@class='star']/a/text()") #图书的评论
            recommend=item.xpath(".//span[@class='tuijian']/text()") #图书的推荐信息
            author=item.xpath(".//div[@class='publisher_info'][1]/a/@title") #图书的作者
            publication_time=item.xpath(".//div[@class='publisher_info'][2]/span/text()") #图书的出版时间            
            press=item.xpath(".//div[@class='publisher_info'][2]/a/text()") #出版社信息
            score=item.xpath(".//div[@class='biaosheng']/span/text()") #评分信息
            price=item.xpath(".//div[@class='price']/p[1]/span[1]/text()") #图书价格
            discount=item.xpath(".//div[@class='price']/p/span[@class='price_s']/text()") #折扣信息
            e_book=item.xpath(".//div[@class='price']/p[@class='price_e']/span/text()") #电子书价格 

            result_list.append(
                {
                    "title":self.join_list(title),
                    "comment":self.join_list(comment),
                    "recommend":self.join_list(recommend),
                    "author":self.join_list(author),
                    "publication_time":self.join_list(publication_time),
                    "press":self.join_list(press),
                    "score":self.join_list(score),
                    "price":self.join_list(price),
                    "discount":self.join_list(discount),
                    "e_book":self.join_list(e_book)
                }
            )

        return result_list

    def insert_data(self,result_list):
        """插入数据到mongodb"""
        self.dangdang.insert_many(result_list) #一次25条数目

def main():
    import json
    d=Dangdang()
    for page in range(1,26):
        items=d.get_dangdang(page=page)
        result=d.parse_item(items=items)
        # print(len(result)) # 浏览器每个页面输出记录条数
        # print(json.dumps(result)) #复制一条,浏览器打开json.cn可以看到json形式
        d.insert_data(result_list=result)

        


if __name__ == '__main__':
    main()

使用了代理以后,抓取的数据会变慢很多

小结

  • 开发环境的配置
  • 了解了关系型数据库和非关系型数据库
  • 安装了MongoDB
  • 安装使用navicat可视化工具,连接了MongoDB数据库
  • 爬虫基础
  • 学习了http和https相关知识
  • 浏览器中观察到了http请求头,以及返回数据,状态码,get请求,post请求
  • request模块——获取网页内容,通过request模块可以请求到网页数据了
  • requests基础模块学习了发送get请求、post请求
  • requests进阶模块中,学习了如何定制请求头、如何获取获取cookie值,如何加载证书,如何保存登录凭据、如何携带代理
  • XPath语句和lxml模块——抽取网页数据,实例化html数据,通过xpath语句获取想要的网页数据
  • 通过XPath语句,在浏览器中使用xpath helper工具来获取网页数据
  • 通过lxml模块,去实例化html数据,并且通过xpath语句,在代码中或许想要的网页数据
  • 爬虫实战——当当网5星排行榜图书数据爬取+将数据保存到mongodb数据库
  • python操作mongodb数据库
  • 项目实战爬取