Python67-爬虫

爬虫的基础知识

爬虫的定义

只要是浏览器可以做的事情,原则上,爬虫都可以帮助我们做,即:浏览器不能够做到的,爬虫也不能做

网络爬虫:又叫网络蜘蛛(spider),网络机器人,就是模拟客户端发送网络请求,接受请求响应,一种按照一定的规则,自动地抓取互联网信息的程序

爬虫的分类

  • 通用爬虫

    通常指搜索引擎的爬虫(面对整个互联网)

  • 聚焦爬虫:

    针对特定网站的爬虫

  • 流程:


    Python67-爬虫_第1张图片
    爬虫的工作流程

ROBOTS协议

网站通过robots协议告诉搜索引擎那些页面可以抓取,那些页面不能抓取

例如:https://www.taobao.com/robots.txt(通常是网站后面加/robots.txt即可以看到,就是一个文本文件)

部分内容如下:

User-agent:  Baiduspider    #用户代理,可以理解为浏览器的身份标识,通过这个字段可以告诉服务器是什么样的程序在请求网站,Baiduspider即百度的搜索引擎
Allow:  /article    #表示允许爬的内容
Allow:  /oshtml
Allow:  /ershou
Allow: /$
Disallow:  /product/    #表示不允许该用户代理爬的内容
Disallow:  /

但是robots只是道德层面的约束

http和https

为了拿到和浏览器一模一样的数据,就必须要知道http和https


Python67-爬虫_第2张图片
在这里插入图片描述
  • http:

    超文本传输协议,明文方式传输,默认端口80

  • https:

    http+ssl(安全套接字层),会对数据进行加密,默认端口443

https更安全,但是性能更低(耗时更长)

浏览器发送http请求的过程

Python67-爬虫_第3张图片
在这里插入图片描述

ps:爬虫在爬取数据的时候,不会主动的请求css、图片、js等资源,就算自己爬取了js的内容,也只是字符串,而不会执行,故, 浏览器渲染出来的内容和爬虫请求的页面并不一样

爬虫要根据当前url地址对应的响应为准,当前url地址的elements的内容和url的响应不一样,特别要注意tbody,经常在elements中有而响应中无

  • 页面上的数据在哪里?

    • 当前url地址对应的相应中
    • 其他url地址对应的相应中,如ajax请求
    • js生成:1、部分数据在响应中,2、全部由js生成

url的格式

host:服务器的ip地址或者是域名
port:服务器的端口
path:访问资源的路径
query-string:参数,发送给http服务器的数据
anchor:锚点(跳转到网页的制定锚点位置,anchor也有主播的意思)

例:http://item.jd.com/11936238.html#product-detail,就是一个带锚点的url,会自动跳转到商品详情,但是要注意,一个页面带锚点和不带锚点的响应是一样的(写爬虫的时候,就可以直接删掉锚点的部分)

http请求格式

Python67-爬虫_第4张图片
在这里插入图片描述

如,在访问百度时,查看request headers的source时,就可以看到如下内容

GET http://www.baidu.com/ HTTP/1.1  
#请求方法:get;url:http:xxxx.com/;协议版本:http1.1,然后换行
Host: www.baidu.com
#请求头部:host;值:www.baidu.com;换行,以下类似
Proxy-Connection: keep-alive    #keep-alive表示支持长链接。为什么要用长连接:不用频繁握手挥手,提高效率
Upgrade-Insecure-Requests: 1    #升级不安全的请求:把http请求转换为https的请求
DNT: 1  #Do not track
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/76.0.3809.100 Safari/537.36  #浏览器的标识。名字/版本号。如果有模拟手机版的请求,改user agent即可,不同的user agent访问相同的url,可能会得到不同的内容
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3  #浏览器告诉服务器自己可以接受什么样的数据
Referer: http://baidu.com/
Accept-Encoding: gzip, deflate  #告诉服务器自己可以接受什么样的压缩方式
Accept-Language: en-US,en;q=0.9 #告诉服务器自己可以接受什么样语言的数据,q:权重,更愿意接受哪种语言
Cookie: BAIDUID=B8BE58B25611B7BBA38ECFE9CE75841F:FG=1; BIDUPSID=B8BE58B25611B7BBA38ECFE9CE75841F; PSTM=1565080210; BD_UPN=12314753; delPer=0; BD_HOME=0;    H_PS_PSSID=26522_1453_21118_29523_29521_29098_29568_28830_29221_26350_22159; BD_CK_SAM=1; PSINO=7; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; COOKIE_SESSION=218_0_3_0_0_7_1_1_1_3_76_2_0_0_0_0_0_0_1565599571%7C3%230_0_1565599571%7C1; rsv_jmp_slow=1565599826516; H_PS_645EC=2c80At1Is237xdMOfC3ju2q0qlWJ%2FFlbD5N50IQeTrCHyIEsZN6yQYBgLHI; B64_BOT=1   #cookie:保存用户的个人信息。ps:cookie和session的区别:cookie保存在浏览器本地,不安全,存储量有上限,session保存在服务器,更安全,往往没有上限。cookie又分为request cookie和reponse cookie,在浏览器中可以查看

除了以上字段,可能还有referer字段,表示当前url是从哪个url过来的;x-request-with字段,表示是ajax异步请求

以上字段中,主要是user agent(模拟浏览器),cookie(反反爬虫)

常见的请求方式

  • get:除了post,基本都用get,更常用

  • post:常用于提交表单的时候(安全),传输大文件的时候(美观)

响应状态码(status code)

  • 200:成功
  • 302/307:临时转移至新的url
  • 404:not found
  • 500:服务器内部错误

字符串知识复习

  • str类型和bytes类型

    • bytes:二进制类型,互联网上数据都是以二进制的方式传输的
  • str:unicode的呈现形式

ps:ascii码是一个字节,unicode编码通常是2个字节,utf-8是unicode的实现方式之一,是一变长的编码方式,可以是1、2、3个字节

编码和解码的方式必须一致,否则会乱码

爬虫部分重要的是理解,而不是记忆


Request模块使用入门

Q:为什么要学习requests,而不是urllib?

  1. requests的底层实现是就urllib,urllib能做的事情,requests都可以做;
  2. requests在python2和python3中通用,方法完全一样;
  3. requests简单易用;
  4. request能够自动帮我们解压(gzip等)网页内容

中文文档api:http://docs.python-requests.org/zh_CN/latest/index.html

基础使用

"""基础入门"""
import requests

r = requests.get('http://www.baidu.com')    #r即为获得的响应。所请求的所有东西都在r中
# 必须要包含协议(http或https);还有dlelete,post等方法

print(r)

print(r.text)   #text是一个属性,其实可以通过他的意思判断,text是一个名字,所以是属性,如果是方法,常为动词
#会自动根据推测的编码方式解码为str

print(r.encoding)   #根据头部推测编码方式,如果猜错了,我们解码的时候就必须自己指定解码的方式

print(r.content)    #也是属性,是一个bytes类型的数据。
print(r.content.decode())   #将bytes类型转换为str类型。默认的解码方式为utf-8
print(r.status_code)    #获取状态码
assert r.status_code == 200   #断言状态码为200,如果断言失败,会报错:assertionerror
#可以用此方法判断请求是否成功

print(r.headers)    #响应头,我们主要关注其中的set-cookie(在本地设置cookie)字段
print(r.request)    #关于对应相应的请求部分,是一个对象
print(r.request.url)    #请求的url地址
print(r.url)    #响应地址,请求的url地址和响应的url地址可能会不一样(因为可能和重定向)
print(r.request.headers)    #请求头,如果不设置,默认的user-agent是python-requests/x.xx.x

with open('baidu_r.txt','w') as f:    #测试:查看默认的user-agent访问时返回的内容
    f.write(r.content.decode())

"""
requests中解编码的方法:
1. r.content.decode()   #content的类型为bytes,必须再次解码
2. r.content.decode('gbk')
3. r.text       #text是按照推测的编码方式进行解码后的数据,他的类型为str
"""

发送带header的请求

具体的header到浏览器中进行查看

"""
为什么请求需要带上header?
    模拟浏览器,欺骗服务器,获取和浏览器一致的内容

header的形式:字典,形式:{request headers冒号前面的值:request headers冒号后面的值},大部分情况,我们带上user-agent即可,少数情况需要cookie
用法:requests.get(url,headers=headers) 
"""

import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}

response = requests.get('https://www.baidu.com',headers=headers)

print(response.content.decode())    #会发现响应中的数据比不带header多许多

发送带参数的请求

#在url中带参数的形式
#例如:在我们百度搜索某东西时,就会带上一大堆参数,但是大部分可能是没有用的,我们可以尝试删除,然后我们在爬虫中带的参数只需要为其中不能删除的部分即可
"""
参数的形式:字典
kw={'wd':'长城'}
用法:requests.get(url,params=kw)
"""
import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}

params = {'wd':'这里是中文'}
#如果参数含中文,其就会被自动编码,编码的后的形式含百分号,我们可以使用url解码来查看原来的内容

r = requests.get('https://www.baidu.com',params=params,headers=headers)
print(r.status_code)
print(r.request.url)
print(r.url)
print(r.content.decode())

#当然,我们也可以直接把参数拼接到url中去,而不单独传参(也不需要手动编码),eg:r = requests.get('https://www.baidu.com/s?wd={}'.formate('传智播客'))

小练习:爬贴吧前1000页

import requests
kw = input('请输入您要爬取的贴吧名:')
url = 'https://tieba.baidu.com/f?kw=%{kw}8&pn='.format(kw=kw)
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}


for i in range(1000):
    url = urlr.formate(str(i*50))
    r = requests.get(url=url, headers=headers)
    with open('./tieba_pages/{}-第{}页.html'.format(kw,i), 'w', encoding='utf-8') as f:
        # 为什么是utf-8,因为r.content.decode()为utf-8的格式
        f.write(r.content.decode())

扁平胜于嵌套:比如,多用列表推倒式替代某些循环


Request深入

发送post请求

用法:

response = requests.post('https://www.baidu.com',data=data,headers=headers)
post时不仅需要地址,还需要我们post的数据,该数据就放在data中
data的形式:字典

使用代理

Python67-爬虫_第5张图片
在这里插入图片描述

正向代理与反向代理
Python67-爬虫_第6张图片
在这里插入图片描述

反向代理:浏览器不知道服务器的地址,比如以上的图例中,浏览器知道的只是nginx服务器,因此,及时有攻击,也只能攻击nginx,不能攻击到我们的服务器

正向代理:浏览器知道服务器的地址

爬虫为什么要使用代理

  • 让服务器以为不是同一个客户端在请求
  • 防止我们的真实地址被泄漏,防止被追究

使用代理

用法:requests.get('http://www.baidu.com',proxies=proxies)
proxies的形式是字典

proxies={
   'htttp':'http://12.34.56.78:8888', #如果请求的是http
   'https':'https://12.34.56.78:8888' #如果请求的是https的地址
}

免费代理的网址:https://proxy.mimvp.com/free.php

代理一般可以分为3种:

  • 透明代理
  • 普匿代理,透明以及普匿,对方是可以追查到我们的真实ip的
  • 高匿代理

要注意,不是所有的ip都支持发送https的请求,有些也不支持发送post请求

代码示例:

"""
0. 准备大量ip地址,组成ip池,随机选择一个ip地址来使用
    - 如何随机选择ip
        - {'ip':ip,'times':0}
        - [{},{},...{}],对这个ip的列表按照使用次数进行排序
        选择使用次数较少的几个ip,从中随机选择一个
1. 检查代理的可用性
    - 使用request添加超时参数,判断ip的质量
    - 在线代理ip质量检测的网站
"""
import requests

proxies = {"http":'http://123.56.74.13:8080'}

headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'
}

r = requests.get('http://www.baidu.com', proxies=proxies,headers=headers)

print(r.status_code)
print(r.request.url)

session和cookie的使用与处理

cookie和session的区别

  • cookie存储在客户的浏览器上,session存储在服务器上
  • cookie的安全性不如session,别人可以分析存放在本地的cokie并进行cookie欺骗
  • session会在一定时间内保存在服务器上,当访问增多,会比较比较占用服务器的性能
  • cookie保存的数据容量有限(通常是4k),很多浏览器限制一个站点最多保存20个cookie

爬虫处理cookie和session

  • 带上 cookie和session的好处:

    能够请求到登录之后的页面

  • 带上cookie和session的弊端:

    一套cookie和session往往和一个用户对应,请求太快、次数太多,容易被服务器识别为爬虫

不需要cookie的时候尽量不去使用cookie

但是为了获取登录之后的页面,我们必须发送带有cookies的请求

携带cookie请求:

  • 携带一堆cookie进行请求,把cookie组成cookie池

如何使用

requests提供了一个叫做session的类,来实现客户端和服务器端的会话保持

  1. 实例化一个session对象:session = requests.session()
  2. 让session发送get或post请求:r = sessioon.get(url=url,data=post_data, headers=headers)

请求登录之后的网站的思路:

  • 实例化session
  • 先使用session发送请求,登陆对应网站,把cookie保存在session中,这里请求时,url应是表单的action的值,如果没有action项,就尝试抓包,看看当我们提交的时候,究竟给哪个网址发送了post请求;post_data是表单中的要提交的数据,其键为name
  • 再使用session请求登录之后才能访问的网站,session能够自动的携带登录成功时保存在其中的cookie,进行请求

案例:访问淘宝的登录后的页面

import requests

sesssion = requests.session()

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}
#注意:在copy User-Agent时,一定要复制全,不能直接在查看的时候copy,容易带上省略号
post_url = 'https://login.m.taobao.com/login.htm'
#post的url一般是在源码中表单的action中找

post_data = {
    'TPL_username':'xxxx',
    'TPL_password2':'xxxx'
}#表单中要填写的项

sesssion.post(url=post_url, data=post_data, headers=headers)

r = sesssion.get('https://h5.m.taobao.com/mlapp/mytaobao.html',headers=headers)

with open('taobao.html', 'w', encoding='utf-8') as f:
    f.write(r.content.decode()) #会发现taobao.html中的代码与我们登录淘宝后的https://h5.m.taobao.com/mlapp/mytaobao.html的代码一样,即成功访问了登录淘宝后的页面

不发送post请求,使用cookie获取登录后的页面

即:直接将cookie加在headers里面,而不必使用session进行post

如:

import requests

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
    'Cookie':'xxxx'
}
url = 'https://i.taobao.com/my_taobao.htm'

r = requests.get(url=url, headers=headers)

print(r.content.decode())

也可以对cookies以参数形式传递,cookies为字典

r = requests.get('http://xxxx',headers=headers, cookies=cookies)
  • cookie过期时间很长的
  • 在cookie过期之前能够拿到所有的数据,比较麻烦
  • 配合其他程序一起使用,其他程序专门获取cookie,当前程序专门请求页面

寻找登录的post地址

  • 在form表单中查找actiond的url地址

    • post的数据是input标签中的name的值作为键,真正的用户名密码作为值的字典,post的url地址就是action对应的url地址
  • 抓包,看看当我们提交的时候,究竟给哪个网址发送了post请求

    • 勾选perserve log按钮,防止页面跳转找不到url

    • 寻找post数据,确定参数

      • 参数不会变:(如何确定参数会不会变?多请求几次),直接用,比如密码不是动态加密的时候

      • 参数会变

        • 参数在当前的响应中
        • 通过js生成:定位到对应的js查看

定位想要的js

  • 法一:对于Chrome浏览器

    • 选择登录按钮(或任意绑定了js事件的对象)
    • Eventlistener
    • 勾选Framework listeners
    • 查看对应的js
    • 找到登录按钮对应的函数
    • (如果遇到某个元素(如:$('.password').value)是干嘛的,可以copy到console中去进行查看;也可以直接对js添加断点)
  • 法二:对于Chrome浏览器

    • 直接通过Chrome中的search all file的搜索url中的关键字
  • 法三

    添加断点的方式来查看js的操作,通过python进行同样的操作,就可以得到js生成的数据

Requests的小技巧

cookie对象与字典的相互转化与url编解码

"""1. 把cookie对象(cookiejar)转化为字典"""
import requests
r = requests.get('http://www.baidu.com')
print(r.cookies)
ret = requests.utils.dict_from_cookiejar(r.cookies)
print(ret)  #输出:{'BDORZ': '27315'}
"""将字典转化为cookiejar"""
print(requests.utils.cookiejar_from_dict(ret))

"""2. url地址的编解码"""
url = 'http://www.baidu.com'
print(requests.utils.quote(url))    #输出:http%3A//www.baidu.com
print(requests.utils.unquote(requests.utils.quote(url)))    #输出:http://www.baidu.com

"""输出结果如下:
]>
{'BDORZ': '27315'}
]>
http%3A//www.baidu.com
http://www.baidu.com
"""

请求SSL证书验证与超时设置

如果某网站使用的是https,但是又没有购买ssl证书,等浏览器访问时就会提示不安全,而当我们使用爬虫爬取的就会报错,此时,我们可以用verify=False来解决

import requests
r = requests.get('https://www.12306.cn/mormhweb/',verify=False, timeout=10) #如果超时,会报错,因此要结合try使用
"""注意:此时不会报错,但是会warning"""

配合状态码判断是否请求成功

assert response.status_code == 200  #如果断言失败,会报错,因此应该结合try使用

重新请求

使用retrying模块,通过装饰器的方式使用

"""重新请求"""
import requests
from retrying import retry

headers= {
            'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'
        }
@retry(stop_max_attempt_number=3)   #即下面的方法最多可以报错3次,如果3次都报错,则程序报错
def _parse_url(url):
    r = requests.get(url,headers=headers,timeout=0.01)
    assert r.status_code == 200
    return r.content.decode()

def parse_url(url):
    try:
        html_str = _parse_url(url)
    except:
        html_str = None
    return html_str
if __name__ == "__main__":
    url = 'http://www.baidu.com'
    print(parse_url(url))

ps:安装第三方模块的方法

  • pip install
  • 下载源码文件,进入解压后的目录:python setup.py install
  • xxx.whl文件,安装方法:pip install xxx.whl

数据提取方法

基础知识

什么是数据提取

从响应中获取我们想要的数据

数据的分类

  • 非结构话数据:html等

    • 处理方法:正则表达式、xpath
  • 结构化数据:json、xml等

    • 处理方法:转化为python数据类型

主要是看结构清不清晰

数据提取之JSON

由于把json数据转化为python内奸数据类型很简单,所以爬虫缀,我们常使用能够返回json数据的url

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它使得人们很容易进行阅读和编写 。同时也方便了机器进行解析和生成,适用于进行数据交换的场景,比如网站前后台间的数据交换

Q:哪里能够找到返回json的url呢?

  • 使用chrome切换到手机页面
  • 抓包手机app的软件

Python67-爬虫_第7张图片
在这里插入图片描述

json.loads与json.dumps

"""
1. json.loads   能够把json字符串转换成python类型
2. json.dumps   能够把python类型转换为json字符串,当我们把数据保存问文本的时候常常需要这么做,如果要使其显示中文,可以使用参数:ensure_ascii=False;还使用使用参数:indent=2,使下一级相对上一级有两个空格的缩进
"""

使用json的注意点:

  • json中的引号都是双引号;

    • 如果不是双引号

      • eval:能实现简单的字符串和python类型的转化
      • replace:把单引号替换为双引号
  • 往一个文件中写如多个json串,不再是一个json串

    • 可以一行写一个json串,按照行来读取

json.load与json.dump

类文件对象:具有read和write方法的对象就是类文件对象,比如:f = open('a.txt','r'),f就是类文件对象(fp)

"""
1. json.load(类文件对象) #类型为dict
2. json.dump(python类型, 类文件对象)   #把python类型放入类文件对象中,也可以使用ensure_ascii和indent参数
"""

json在数据交换中起到了一个载体的作用,承载着相互传递的数据


Python67-爬虫_第8张图片
在这里插入图片描述

案例:爬取豆瓣

import requests
from pprint import pprint   #pprint:pretty print,实现美化输出
import json

from retrying import retry

url = 'https://m.douban.com/rexxar/api/v2/skynet/playlists?from_rexxar=true&for_mobile=1'

headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36',
    # 'Sec-Fetch-Mode': 'cors'
    'Referer': 'https://m.douban.com/movie/beta'
    #在本次爬取过程中,必须加上Referer才行
}
@retry(stop_max_attempt_number=3)
def parse_url(url):
    r = requests.get(url,headers=headers, timeout=10)
    assert r.status_code == 200
    return r.content.decode()
    
resp_html = parse_url(url)
p_resp = json.loads(resp_html)
pprint(p_resp)
with open('douban.json','w', encoding='utf-8') as f:
    f.write(json.dumps(p_resp, indent=2, ensure_ascii=False))

douban.json中的部分内容如下:


Python67-爬虫_第9张图片
在这里插入图片描述

案例:爬取36kr

"""爬取36kr"""
import requests,json
from pprint import pprint
import re
url = 'https://36kr.com/'

headers = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36'
}
r = requests.get(url=url, headers=headers,timeout=3)
html_str = r.content.decode()
reg = '(.*?)'    #新闻的标题是直接在html中的
ret = re.findall(reg, html_str)
pprint(ret)

部分输出结果如下:


Python67-爬虫_第10张图片
在这里插入图片描述

爬虫思路总结

  • 通常,我们访问某个网站时,得到的是其主页的url
  • 得到了主页的url后,观察我们所需要的数据是否在主页对应的响应中,如果在,直接利用主页的url爬取
  • 如果不在主页的url中,查找我们需要的数据,得到其对应url,用该url进行数据的爬取
  • 如果相应数据不是在html中,而是json中,用json.loads对数据进行处理

正则表达式复习

所谓正则表达式,即:事先定义好一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤

常用的正则表达式的方法有

  • re.compile:编译
  • pattern.math:从头找一个
  • pattern.search:找一个
  • pattern.findall:找所以
  • pattern.sub:替换
Python67-爬虫_第11张图片
在这里插入图片描述

说明:

  • .的Dotall即模式即是在匹配时加上re.Dotall参数,或者re.S,使.能够匹配任意字符

  • 记忆:d:digit;s:space

  • sub的使用,re.sub(reg, new_str, old_str),将匹配到的内容替换为new_str

  • re.findall('a(.*)b', 'str'),能够返回括号中的内容,括号前后的内容起到定位和过滤的效果

  • r'a\nb' 可以匹配'a\nb';r'a\nb'而不能匹配'a\nb',r可以忽略转义符号带来的影响,待匹配的字符串里面有 几个\,正则表达式里面也写几个\即可

  • compile的作用

    • 将对应正则表达式能够匹配到的内容放到内存中去,加快匹配的速度
    • 使用方法:re.compile(reg)
  • compile和sub的结合使用

    b = hello1world2
    p = re.compile('\d')
    p.findall(b)
    p.sub('_',b)    #将b中的所有数字替换为下划线
    

    ps:如果是对.进行编译,若想使其能够匹配换行符等,则re.S需要加在编译的使用,而不是匹配的时候

贪婪模式与非贪婪模式

  • 非贪婪模式:.*?或者.+?
  • 贪婪模式:.*或者.+

XPATH和lXML

基础知识

lxml是一款高性能的python HTML/XML解析器,利用xpath,我们可以快速的定位特定元素以及获取节点信息

什么是xpath

xpath(XML Path Language)是一门在HTML/XML文档中查找信息的语言(既然是一种语言,就有自己的语法),克用来在html/xml中对元素和属性进行遍历

W3School官方文档:http://www.w3school.com.cn/xpath/index.asp

xml与html对比

Python67-爬虫_第12张图片
在这里插入图片描述

节点的概念:每个xml标签都称之为节点,比如下图中的</code>等</p> <div class="image-package"> <div class="image-container" style="max-width: 569px; max-height: 348px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/22c7b261e4234bb5b6af40db500f753d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/22c7b261e4234bb5b6af40db500f753d.jpg" width="569" height="348" alt="Python67-爬虫_第13张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>book节点是title等节点的父节点,title和author等是兄弟节点,此外,还有祖先节点等概念</p> <p><strong>常用节点选择工具</strong></p> <ul> <li>Chrome插件XPATH Helper</li> <li>开源的XPATH表达式编辑工具:XMLQuire(XML格式文件可用)</li> <li>FireFox插件 XPath Checker</li> </ul> <h2>XPATH语法</h2> <p>XPATH使用路径表达式来选取xml文档中的节点或者节点集。这些<strong>路径表达式</strong>和我们在常规的<strong>电脑文件系统</strong>中看到的表达式非常类似</p> <p><code>注意:我们写xpath的时候,看的是请求页的响应,而不是elements</code></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 271px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/01b7ee2450224bfe91b8d4f3abd5f8cc.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/01b7ee2450224bfe91b8d4f3abd5f8cc.jpg" width="650" height="238" alt="Python67-爬虫_第14张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>使用Chrome插件的时候,当我们选中标签,该标签会添加属性class='xh-highlight'</p> <pre><code class="python">/html 即表示从根节点开始选中html标签 /html/head 选中html标签下的head标签 /html/head/link 选中html标签下的head标签中的所有link标签 </code></pre> <p><strong><code>xpath学习重点</code></strong></p> <ul> <li><p>使用xpath helper或者是Chrome浏览器中的copy xpath都是从element中提取的数据,但是爬虫获取的是url对应的响应,往往和elements不一样</p></li> <li> <p>获取属性</p> <ul> <li> <code>/html/head/link/@href</code> 选择html标签下的head标签下的(所有)link标签中的href属性的值</li> </ul> </li> <li> <p>获取文本</p> <ul> <li> <code>/html/head/link/text()</code> 即选取标签中的内容,innerHtml</li> <li> <code>/html//text()</code> 获取html下所有的标签文本</li> <li> <code>//a[text()='下一页']</code>选择文本为下一页三个字的a标签</li> </ul> </li> <li> <p>从当前节点往下开始选择与使用@进行元素的定位</p> <ul> <li> <code>//li</code> 选中文档中所有的li标签</li> <li> <code>//li//a</code> 文档中的所有li中的所有a标签</li> <li> <code>//ul[@id='detail-list']/li</code> 选中文档中的id为'detail-list'的ul标签下的li标签;如果没有id,也可以@class等</li> </ul> </li> </ul> <p><strong>选择特定节点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 433px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9dbed70f7f924040a4471671245e7734.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9dbed70f7f924040a4471671245e7734.jpg" width="650" height="350" alt="Python67-爬虫_第15张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>上图中的部分说明:</p> <ul> <li> <code>/bookstore/book[price>35.00]</code>book用的是子节点中的price标签进行的修饰,此处price的形式为:<code><price>35.00</price></code> </li> </ul> <p><strong>选择未知节点</strong></p> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 406px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/d5c42a02763a40fab2cb22b89162890c.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/d5c42a02763a40fab2cb22b89162890c.jpg" width="650" height="352" alt="Python67-爬虫_第16张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <strong>选择若干路径(或的运用)</strong> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 225px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/18cf4ee74e414de4a405c3b280a57984.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/18cf4ee74e414de4a405c3b280a57984.jpg" width="650" height="182" alt="Python67-爬虫_第17张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>lXML库</h2> <p><strong>使用入门</strong></p> <pre><code class="python">""" 1. 导入lxml的etree库:from lxml import etree,注意,如果是在pycharm中,可能会报红,但是不影响使用 2. 利用etree.HTML,将字符串转化为Element对象 3. Element对象具有xpath的方法:html = etree.HTML(text) html.xpath('字符串格式的xpath语法') """ </code></pre> <p>应用举例:</p> <pre><code class="python">from lxml import etree from pprint import pprint text = """ <tr> <td class="opr-toplist1-right">586万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">539万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">444万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">395万<i class="opr-toplist1-st c-icon "></i></td> """ html = etree.HTML(text) #html为一个Element对象 pprint(html) #查看element对象中包含的字符串(bytes类型) pprint(etree.tostring(html).decode()) #会发现把缺少的标签进行了补全,包括html和body标签 print(html.xpath('//td/text()')) #这里的html是上面etree.HTML(text)获得的对象,结果为列表 #只要是element对象,就可以使用xpath进行数据的提取 </code></pre> <p><strong>lxml注意点</strong></p> <ul> <li> <p>lxml可以自动修正html代码(但是不一定能正确修正,也可能改错了)</p> <ul> <li>使用etree.tostring查看修改后的样子,根据修改之后的html字符串写xpath</li> </ul> </li> <li> <p>提取页面数据的思路</p> <ul> <li>先分组,渠道:一个包含分组标签的列表</li> <li>遍历:取其中每一组进行数据的提取,不会造成数据对应错乱</li> </ul> </li> </ul> <p><strong>xpath的包含</strong></p> <ul> <li> <code>//div[contains(@class='li')]</code>获取包含有li样式类的标签的标签</li> </ul> <p><strong>爬虫的思路总结</strong></p> <ol> <li> <p>准备url</p> <ol> <li> <p>准备start_url</p> <ul> <li><p>url地址规律不明显,总数不确定</p></li> <li> <p>通过代码提取下一页url</p> <ul> <li>xpath:url在当前的响应里面</li> <li>寻找url地址,部分参数在当前的响应中,比如当前页面数和总的页码数(eg:通过js生成)</li> </ul> </li> </ul> </li> <li> <p>准备url_list</p> <ul> <li>页码总数明确</li> <li>url地址规律明显</li> </ul> </li> </ol> </li> <li> <p>发送请求,获取响应</p> <ul> <li><p>添加随机的User-Agent:反反爬虫</p></li> <li><p>添加随机的代理ip:反反爬虫</p></li> <li> <p>在对方判断出我们是爬虫之后,添加更多的header字段,包括cookie</p> <ul> <li><p>cookie的处理可以通过session来解决</p></li> <li> <p>准备一堆能用的cookie,组成cookie池</p> <ul> <li> <p>如果不登录,准备当开始能够请求对方网站的cookie,即接受对方网站设置在response的cookie</p> <ul> <li>下一次请求的时候,使用之前的列表中的cookie来请求</li> <li>即:专门用一个小程序来获取cookie,爬取数据再用另一个程序</li> </ul> </li> <li> <p>如果登录</p> <ul> <li>准备一堆账号</li> <li>使用程序获取每个账号的cookie</li> <li>之后请求登录之后才能访问的网站随机的选择cookie</li> </ul> </li> </ul> </li> </ul> </li> </ul> </li> <li> <p>提取数据</p> <ul> <li> <p>确定数据的位置</p> <ul> <li> <p>如果数据在当前的url地址中</p> <ul> <li> <p>提取的是列表页的数据</p> <ul> <li>直接请求列表页的url地址,不用进入详情页</li> </ul> </li> <li> <p>提取的是详情页的数据</p> <ul> <li>确定url地址</li> <li>发送请求</li> <li>提取数据</li> <li>返回</li> </ul> </li> </ul> </li> <li> <p>如果数据不在当前的url地址中</p> <ul> <li>在其他的响应中,寻找数据的位置</li> <li>使用chrome的过滤条件,选择除了js,css,img之外的按钮(但是可能出错)</li> <li>使用chrome的search all file,搜索数字和英文(有时候不支持搜索中文)</li> </ul> </li> </ul> </li> <li> <p>数据的提取</p> <ul> <li>xpath,从html中提取整块数据,先分组,之后没一组再提取</li> <li>json</li> <li>re,提取max_time,price,html中的json字符串</li> </ul> </li> </ul> </li> <li> <p>保存</p> <ul> <li>保存在本地,text、json、csv</li> <li>保存在数据库</li> </ul> </li> </ol> <h2>CSV</h2> <p>逗号分隔值,一种文件后缀,以纯文本的形式存储表格数据</p> <p>其文件中的一行对应表格的一行,以逗号分隔列</p> <hr> <h1>多线程爬虫</h1> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 231px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/82e6f89a01e942e29f3a0faffd424eb1.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/82e6f89a01e942e29f3a0faffd424eb1.jpg" width="650" height="200" alt="Python67-爬虫_第18张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <hr> <h1>动态HTML技术</h1> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 279px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/eea363f1902f435caf721c7141226d4d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/eea363f1902f435caf721c7141226d4d.jpg" width="650" height="224" alt="Python67-爬虫_第19张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>Selenium和PhantomJS</h2> <ul> <li> <p>Selenium</p> <p>Selenium是一个Web的自动化测试工具,可以控制一些浏览器(比如phantomJS),可以接受指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏</p> </li> <li> <p>PhantomJS</p> <p>phantomJS是一个基于Webkit的“无界面”浏览器,它会把网站加载到内存并执行页面上的javascript</p> </li> </ul> <p>下载地址:http://phantomjs.org/download.html</p> <h3>入门</h3> <pre><code class="python">"""1. 加载网页""" from selenium import webdriver driver = webdriver.PhantomJS("xxxx/phantom.exe") """除了PhantomJS,还有Chrome,FireFox等""" driver.get("http://www.baiud.com/") driver.save_screenshot("长城.pnh") """2. 定位和操作""" driver.find_element_byid("kw").send_keys("长城") drvier.finde_element_by_id("su").click() """3. 查看和请求信息""" driver.page_source() driver.get_cookies() driver.current_url() """4. 退出""" driver.close() #退出当前页面 driver.quit() #退出浏览器 """5. 其他""" #ps:无论是使用PhantomJS还是Chrome或是FireFox,driver的操作是一样的 </code></pre> <p><strong>基础使用示例</strong></p> <p>ps:chromedriver的下载地址(注意:版本一定要和你安装的Chrome浏览器的版本号一致):http://npm.taobao.org/mirrors/chromedriver/</p> <pre><code class="python">from selenium import webdriver """ selenium请求的速度很慢,因为是使用浏览器,会请求js、css等 """ phantom_path = r"D:\Green\phantomjs-2.1.1-windows\bin\phantomjs.exe" """在使用phatnomjs时,报了unexpected exit, status code 0的错误,尚未找到原因""" chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" """注意:这里一定要是chromedriver.exe,而不是chrome.exe""" driver = webdriver.Chrome(executable_path=chrome_path) #实例化对象 # driver.maximize_window() #最大化窗口 driver.set_window_size(width=1920,height=1080) #设置窗口大小 driver.get("http://www.baidu.com") driver.find_element_by_id('kw').send_keys("python") #kw是百度的输入框的表单的id;send_keys就是往一个input标签里面输入内容 #以上的一行代码就可以时Chrome自己百度搜索python driver.find_element_by_id('su').click() #su是百度一下的按钮的id #click实现对按钮的点击 """获取当前的url""" print(driver.current_url) #注意:因为已经click了,所以是click后的地址 """截屏""" driver.save_screenshot("./baidu_python.png") """在本次截屏中,由于截屏太快而网页加载太慢,截屏的图中未能截到百度出来的结果""" """driver获取cookie""" cookies = driver.get_cookies() print(cookies) cookies = {i['name']:i['value'] for i in cookies} #使用字典推导式重新生成requests模块能用的cookies print(cookies) """获取html字符串""" """即elements""" print(driver.page_source) #page_source是一个属性,获得html字符串后,就可以直接交给xpath """退出当前页面""" driver.close() #如果只有一个窗口,close就是退出浏览器 """退出浏览器""" driver.quit() </code></pre> <p><strong>示例二</strong></p> <pre><code class="python">from selenium import webdriver from time import sleep chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get('https://www.qiushibaike.com/text/page/1/') ret = driver.find_elements_by_xpath(".//div[@id='content-left']/div") for r in ret: print(r.find_element_by_xpath("./a[1]/div[@class='content']/span").text) """通过text属性获取文本""" print(r.find_element_by_xpath("./a[1]").get_attribute("href")) """通过get_attribute获取属性""" driver.quit() </code></pre> <p><strong>元素的定位方法</strong></p> <ul> <li>find_element_by_id 返回一个</li> <li>find_elements_by_id 返回一个列表</li> <li>find_elements_by_link_text</li> <li>find_elements_by_partial_link_text</li> <li>find_elements_by_tag_name</li> <li>find_element_by_class_name</li> <li>find_elements_by_class_name</li> <li>find_elements_by_css_selector</li> </ul> <p>注意:</p> <ul> <li>获取文本或属性时,需要先定位到对应元素,再使用text属性或者get_attribute方法</li> <li>element返回一个,elements返回列表</li> <li>link_text和partial_link_text的区别:全部文本和包含的某个文本,即partial可以只写部分文本,而link_text需要写完整</li> <li>by_css_selector的用法:#food span.dairy.aged</li> <li>by_xpath中获取属性和文本需要使用get_attribute()和.text</li> <li>selenium使用class定位标签的时候,只需要其中的一个class样式名即可,而xpath必须要写所有的class样式类名</li> </ul> <p>示例:</p> <pre><code class="python">from selenium import webdriver from time import sleep chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get('https://www.qiushibaike.com/text/page/1/') ret = driver.find_elements_by_xpath(".//div[@id='content-left']/div") for r in ret: print(r.find_element_by_xpath("./a[1]/div[@class='content']/span").text) """通过text属性获取文本""" print(r.find_element_by_xpath("./a[1]").get_attribute("href")) """通过get_attribut获取属性""" print('-'*50) """find_element_by_link_text""" """根据标签里面的文字获取元素""" print(driver.find_element_by_link_text("下一页").get_attribute('href')) """partial_link_text""" print(driver.find_element_by_partial_link_text("下一").get_attribute('href')) """以上两行代码获得的东西相同""" driver.quit() </code></pre> <h3>深入</h3> <p><strong>iframe</strong></p> <p>iframe或frame里面的html代码和外面的html代码实质上是两个不同的页面,因此,有时候我们在定位元素时,明明elements里面有,但是会定位失败</p> <p>解决办法:使用driver.switch_to.frame或driver.switch_to_frame(已经被弃用)方法切换到对应frame中去</p> <p>driver.switch_to.frame的使用说明:</p> <pre><code class="python">def frame(self, frame_reference): """ Switches focus to the specified frame, by index, name, or webelement. :Args: - frame_reference: The name of the window to switch to, an integer representing the index, or a webelement that is an (i)frame to switch to. :Usage: driver.switch_to.frame('frame_name') driver.switch_to.frame(1) driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0]) """ 源码 </code></pre> <p>代码示例:豆瓣登录</p> <pre><code class="python">from selenium import webdriver import time chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get("https://douban.com/") login_frame = driver.find_element_by_xpath("//iframe[1]") driver.switch_to.frame(login_frame) driver.find_element_by_class_name("account-tab-account").click() driver.find_element_by_id("username").send_keys("784542623@qq.com") driver.find_element_by_id("password").send_keys("zhoudawei123") driver.find_element_by_class_name("btn-account").click() time.sleep(10) #暂停以手动进行验证 """获取cookies""" cookies = {i['name']:i['value'] for i in driver.get_cookies()} print(cookies) time.sleep(3) driver.quit() </code></pre> <p><strong>注意</strong></p> <ul> <li>selenium获取的页面数据 是浏览器中elements的内容</li> <li>selenium请求第一页的时候,会等待页面加载完了之后再获取数据,但是在点击翻页之后,会立马获取数据,此时可能由于页面还没有加载完而报错</li> </ul> <h3>其他</h3> <ul> <li> <p>cookies相关用法</p> <ul> <li>{cookie['name']:cookie['value'] for cookie in driverr.get_cookies()} 获取字典形式的cookie</li> <li>driver.delete_cookie('cookiename')</li> <li>driver.delete_all_cookies()</li> </ul> </li> <li> <p>页面等待</p> <p>页面等待的原因:如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,这个时候就需要一个等待时间</p> <ul> <li>强制等待:time.sleep(10)</li> <li>显示等待(了解)</li> <li>隐式等待(了解)</li> </ul> </li> </ul> <hr> <h1>Tesseract的使用</h1> <ol> <li><p>tesseract是一个<strong>将图像翻译成文字的OCR库</strong>,ocr:optical character recognition</p></li> <li> <p>在python中安装tesseract模块:pip install pytesseract,使用方法如下:</p> <pre><code class="python">import pytesseract from PIL import Image image = Image.open(jpg) #jpg为图片的地址 pytesseract.image_to_string(image) </code></pre> </li> </ol> <p>使用tesseract和PIL,我们就可以使程序能够识别验证码(当然,也可以通过打码平台进行验证码的识别)</p> <p>示例:对如下图片进行识别</p> <div class="image-package"> <div class="image-container" style="max-width: 413px; max-height: 342px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/36d3f32448ae4bfeb22f263c42eb8e47.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/36d3f32448ae4bfeb22f263c42eb8e47.jpg" width="413" height="342" alt="Python67-爬虫_第20张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <pre><code class="python">import pytesseract from PIL import Image img_url = "verify_code.jpg" pytesseract.pytesseract.tesseract_cmd = r'D:\Tesseract-OCR\tesseract.exe' image = Image.open(img_url) print(pytesseract.image_to_string(image)) """ 使用过程中的问题: 1. 电脑上必须先安装tesseract客户端,然后才能结合pytesseract使用 2. 将tesseract加入环境变量 3. 在环境变量中新建项:名字:TESSDATA_PREFIX,值:你的tesseract的安装目录(tessdata的父级目录) 4. 在代码中加入:pytesseract.pytesseract.tesseract_cmd = r"tesseract的安装路径\tesseract.exe" 5. 默认只识别英语,如果要识别其他语言,需要下载相关语言的.traneddata文件到Tesseract的安装目录下的tessdata路径下:https://github.com/tesseract-ocr/tesseract/wiki/Data-Files """ """识别结果如下: Happy Birthday """ </code></pre> <hr> <h1>Mongodb</h1> <p>注意:以下用到的集合大多为stu(学生信息),少部分为products</p> <h2>基础入门</h2> <p>Mongodb是一种NoSQL数据库</p> <p>mysql的扩展性差,大数据下IO压力大,表结构更改困难;而nosql易扩展,大数据量高性能,灵活的数据模型,高可用</p> <p>下载地址:https://www.mongodb.com/download-center/community</p> <p><strong>mongodb的使用</strong></p> <ul> <li> <p>在终端运行<code>MongoDB\bin\mongod.exe --dbpath D:\MongoDB\data</code>,其中,D:\MongoDB是安装路径,(注意:下图中我在安装时把MongoDB写成了MonggoDB</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 348px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9d3ddcb1a40c4fa89123ff99633ddbe3.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9d3ddcb1a40c4fa89123ff99633ddbe3.jpg" width="650" height="236" alt="Python67-爬虫_第21张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>因为在安装时我们默认安装了MongoDB Compass Community,我们打开该软件,直接连接即可,不用对其做任何更改,成功后如图所示:</li> </ul> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 381px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/018a70f3e9174b77916c6f5dab313d80.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/018a70f3e9174b77916c6f5dab313d80.jpg" width="650" height="339" alt="Python67-爬虫_第22张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>如果我们要使用数据库,还需要将安装目录下小bin目录加入系统的环境变量,然后在终端输入mongo即可</li> </ul> </li> </ul> <p>ps:在mongo的交互环境中,可以通过tab键进行命令的补全</p> <p><strong>database的基础命令</strong></p> <ul> <li>查看当前数据库:db</li> <li>查看所有的数据库:show dbs或show databases</li> <li>切换数据库:use db_name</li> <li>删除当前数据库:db.dropDatabase()</li> </ul> <p>在mongodb里面,是没有表的概念的,数据是存储在集合中</p> <p>向不存在的集合中第一次插入数据时,集合会被创建出来</p> <p>手动创建集合:</p> <ul> <li>db.createCollection(name,options)</li> <li>options是一个字典,例如:{size:10, capped:true} #表示存储的上限为10条数据,capped为true表示当数据达到上限时,会覆盖之前的数据</li> </ul> <ul> <li>查看集合:show collections</li> <li>删除集合:db.collection_name.drop()</li> </ul> <p><strong>mongodb中的数据类型</strong></p> <ul> <li>ObjectID:文档id,所谓文档,即我们即将存储到数据库中的一个个的字典</li> <li>String</li> <li>Boolean:必须是小写,true或false</li> <li>Integer</li> <li>Double</li> <li>Arrays</li> <li>Object:用于嵌入式的文档,即一个值为一个文档</li> <li>Null</li> <li>Timestamp:时间戳</li> <li>Date:创建日期的格式:new Date("2019-02-01")</li> </ul> <p>注意点:</p> <ul> <li>每个文档的都有一个属性,为_id,保证文档的唯一性</li> <li>可以自己设置_id插入文档,如果没有提供,自动生成,类型为Object_id</li> <li>objecID是一个12字节的16进制数,4:时间戳,3:机器id,2:mongodb的服务进程id,3:简单的增量值</li> </ul> <p><strong>数据的操作</strong></p> <ul> <li>用insert插入:先use数据库,<code>db.集合名.insert({"name":"zhang3", "age":23})</code>,实质上插入的数据不是字典,而是json,因此键可以不用引号。insert的时候如果文档id已经存在,会报错</li> <li>查看表中的数据:<code>db.表名.find()</code> </li> <li>用save进行数据的插入:<code>db.集合名.save(要插入的数据)</code>,如果文档id(对应我们要插入的数据)已经存在,就是修改,否则新增</li> <li>查看集合中的数据:<code>db.集合名称.find()</code> </li> <li>更新:db.集合名称.<code>update(<query>,<update>,{multi:<boolean>})</code>,用法如下: <pre><code class="python">db.stu.upate({name:'hr'}, {name:'mnc'})#更新一条的全部 db.stu.update({name:'hr'}, {$set:{name:'mnc'}}) #更新一条中的对应键值 """这种更改用得更多""" db.stu.update({},{$set:{gender:0}}, {multi:true}) #更新全部 """注意:multi这个参数必须和$符号一起使用才有效果""" </code></pre> </li> <li>使用remove删除数据:db.集合名.remove({name:"zhang3"},{justOne:true}),表示只删除一条名字为zhang3的数据,如果不指定justOne,就是删除全部符合的数据</li> </ul> <h2>高级查询</h2> <p><strong>find</strong></p> <pre><code class="python">"""find""" db.stu.find() #查询所有的数据 db.stu.find({age:23}) #查询满足条件的数据 db.stu.findOne({age:23}) #查询满足条件的一个数据 db.stu.find().pretty() #对数据进行美化 </code></pre> <p><strong>比较运算符</strong></p> <pre><code class="python">1. 等于:默认是等于判断,没有运算符 2. 小于:$lt(less than) 3. 大于:$gt(greater than) 4. 小于等于:$lte(less than equal) 5. 大于等于:$gte(greater than equal) 6. 不等于:$ne(not equal) </code></pre> <p>使用举例:</p> <pre><code class="python">db.stu.find({age:{$le(18)}}) #查询年龄小于18的 </code></pre> <p><strong>范围运算符</strong></p> <pre><code class="python">1. $in:在某个范围 2. $nin:不在某个范围 </code></pre> <p>用法举例:</p> <pre><code class="python">db.stu.find({age:{$in[18,28,38]}}) #查询年龄为18或28或38的 </code></pre> <p><strong>逻辑运算符</strong></p> <pre><code class="python">and:直接写多个条件即可,例:db.stu.find({age:{$gte:18},gender:true}) or:使用$or,值为数组,数组中的每个元素为json,例:查询年龄大于18或性别为false的数据:db.stu.find({$or:[{age:{$gt:18}},{gender:{false}}]}) </code></pre> <p><strong>正则表达式</strong></p> <pre><code class="python">1. db.products.find({sku:/^abc/}) #查询以abc开头的sku 2. db.products.find({sku:{$regex:"789$"}}) #查询以789结尾的sku </code></pre> <p><strong>limit和skip</strong></p> <pre><code class="python">1. db.stu.find().limit(2) #查询两个学生的信息 2. db.stu.find().skip(2) #跳过前两个学生的信息 3. db.stu.find().skip(2).limit(4) #先跳过2个,再查找4个 </code></pre> <p><strong>自定义查询</strong></p> <pre><code class="python">db.stu.find({$where:function(){ return this.age > 30; }}) #查询年龄大于30的学生 </code></pre> <p><strong>投影</strong></p> <p>即返回满足条件的数据中的部分内容,而不是返回整条数据</p> <pre><code class="python">db.stu.find({$where:function(){ return this.age > 30, {name:1,hometown:1}; }}) #查询年龄大于30的学生,并返回其名字和hometown,其中,this是指从前到后的每一条数据;如果省略{name:xxx}就会返回该条数据的全部内容 db.stu.find({},{_id:0,name:1,hometown:1}) #显示所有数据的name和hometown,不显示_id,但是要注意,只有_id可以使用0;一般对其他字段来说,要显示的写1,不显示的不写即可,_id默认是会显示的 </code></pre> <p><strong>排序</strong></p> <pre><code class="python">db.stu.find().sort({age:-1}) #按年龄的降序排列,如果是{age:1}就是按按铃升序排序 db.stu.find().sort({age:1,gender:-1}) #按年龄的升序排列,如果年龄相同,按gender的降序排列 </code></pre> <p><strong>count方法</strong></p> <pre><code class="python">db.stu.find({条件}).count() #查看满足条件的数据有多少条 db.stu.count({条件}) </code></pre> <p><strong>消除重复</strong></p> <pre><code class="python">db.stu.distinct("去重字段",{条件}) db.stu.distinct("hometown",{age:{$gt:18}}) #查看年龄大于18的人都来自哪几个地方 </code></pre> <h2>聚合aggregate</h2> <p>聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。<br> db.集合名称.aggregate({管道:{表达式}})</p> <p>所谓管道,即把上一次的输出结果作为下一次的输入数据</p> <p><strong>常用管道如下</strong>:</p> <ul> <li>$group: 将集合中的⽂档分组, 可⽤于统计结果</li> <li>$match: 过滤数据, 只输出符合条件的⽂档,match:匹配</li> <li>$project: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果</li> <li>$sort: 将输⼊⽂档排序后输出</li> <li>$limit: 限制聚合管道返回的⽂档数</li> <li>$skip: 跳过指定数量的⽂档, 并返回余下的⽂档</li> <li>$unwind: 将数组类型的字段进⾏拆分,即展开的意思</li> </ul> <p><strong>表达式</strong></p> <p>语法:表达式:'$列名'<br> 常⽤表达式:</p> <ul> <li> sum:1 表示以⼀倍计数</li> <li>$avg: 计算平均值</li> <li>$min: 获取最⼩值</li> <li>$max: 获取最⼤值</li> <li>$push: 在结果⽂档中插⼊值到⼀个数组中</li> <li>$first: 根据资源⽂档的排序获取第⼀个⽂档数据</li> <li>$last: 根据资源⽂档的排序获取最后⼀个⽂档数据</li> </ul> <p><strong>用法示例</strong>:</p> <pre><code class="python">"""group的使用""" db.Temp.aggregate( {$group:{_id:"$gender"}} ) #按性别分组 """输出结果: { "_id" : 1 } { "_id" : 0 } """ db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1}}} ) #按性别分组并计数,sum:1是指每条数据作为1 """输出结果如下: { "_id" : 1, "count" : 7 } { "_id" : 0, "count" : 1 } """ """注意:_id和count的键不能变""" db.Temp.aggregate( {$group:{_id:"$gender", count:{$sum:1}, avg_age:{$avg:"$age"}}} ) #按年龄分组并计数,再分别计算其年龄的平均值 """结果如下: { "_id" : 1, "count" : 7, "avg_age" : 22.857142857142858 } { "_id" : 0, "count" : 1, "avg_age" : 32 } """ """注意:如果分组时_id:null,则会将整个文档作为一个分组""" """管道的使用""" db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1},avg_age:{$avg:"$age"}}}, {$project:{gender:"$_id",count:"$count",avg_age:"$avg_age"}} ) #将group的输出再作为project的输入,因为前面已经有了_id,count,avg_age等输出键,所以在后面的管道中可以直接使用(此例中用了_id和avg_age),也可以使用1使其显示,0使其不显示 """输出结果如下 { "count" : 7, "gender" : 1, "avg_age" : 22.857142857142858 } { "count" : 1, "gender" : 0, "avg_age" : 32 } """ """match管道的使用""" #为什么使用match过滤而不是find的过滤?match可以将其数据交给下一个管道处理,而find不行 db.Temp.aggregate( {$match:{age:{$gt:20}}}, {$group:{_id:"$gender",count:{$sum:1}}}, {$project:{_id:0,gender:"$_id",count:1}} ) #先选择年龄大于20的数据;然后将其交给group管道处理,按照性别分组,对每组数据进行计数;然后再将其数据交给project处理,让_id字段显示为性别,不显示_id字段,显示count字段 """sort管道的使用""" db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1}}}, {$sort:{count:-1}} ) #将第一个管道的数据按照其count字段的逆序排列,和find中的排序使用方式一样 """结果如下: { "_id" : 1, "count" : 7 } { "_id" : 0, "count" : 1 } """ """skip和limit的用法示例: {$limit:2} {$skip:5} """ """unwind使用使例:""" eg:假设某条数据的size字段为:['S','M','L'],要将其拆分 db.Temp.aggregate( {$match:{size:["S","M","L"]}}, #先找到该数据 {$unwind:"$size"} ) """结果如下: { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "S" } { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "M" } { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "L" } """ </code></pre> <p>小练习:</p> <pre><code class="python">"""数据和需求: { "country" : "china", "province" : "sh", "userid" : "a" } { "country" : "china", "province" : "sh", "userid" : "b" } { "country" : "china", "province" : "sh", "userid" : "a" } { "country" : "china", "province" : "sh", "userid" : "c" } { "country" : "china", "province" : "bj", "userid" : "da" } { "country" : "china", "province" : "bj", "userid" : "fa" } 需求:统计出每个country/province下的userid的数量(同一个userid只统计一次) """ db.Exci.aggregate( {$group:{_id:{userid:"$userid",province:"$province",country:"$country"}}}, #先按照三个字段分组(去重) {$group:{_id:{country:"$_id.country",province:"$_id.province"},count:{$sum:1}}}, {$project:{_id:0,country:"$_id.country",province:"$_id.province",count:"$count"}} ) """注意:取字典里面的元素用(.)操作符;group的_id可以为字典""" """三个管道处理过后的数据分别如下: #第一次group { "_id" : { "userid" : "a", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "b", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "c", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "da", "province" : "bj", "country" : "china" } } { "_id" : { "userid" : "fa", "province" : "bj", "country" : "china" } } #第二次group { "_id" : { "country" : "china", "province" : "bj" }, "count" : 2 } { "_id" : { "country" : "china", "province" : "sh" }, "count" : 3 } #最终结果 { "country" : "china", "province" : "sh", "count" : 3 } { "country" : "china", "province" : "bj", "count" : 2 } """ """也可以写成如下形式:""" db.Temp.aggregate( {$match:{size:["S","M","L"]}}, {$unwind:{path:"$size",preserveNullAndEmptyArrays:true}} ) #path字段是要拆分的字段,参数表示保存Null和EmptyArrays,因为如果是原数据中有某字段为null或[],那么在拆分一个数据后,表中原来含nul或[]的那几条数据会消失 </code></pre> <h2>索引</h2> <p>作用:提升查询速度</p> <p>db.t1.find({查询条件})<br> db.t1.find({查询条件}).explain('executionStats') 可以通过其中的"executionTimeMillisEstimate"字段查看查询所花费的时间</p> <p><strong>建立索引</strong></p> <ul> <li><p>语法:db.集合.ensureIndex({属性1:1}, {unique:true}) 其中,1表示升序,-1表示降序,一般来说,升序或降序的影响不大;unique字段可以省略,加上后,保证索引唯一,即:如果我们用name作为索引,那么在集合中就不能有name值相同的数据;</p></li> <li><p>联合索引,即ensureIndex的参数为{属性1:1或-1, 属性2:-1或1},联合索引是为了保证数据的唯一性</p></li> <li><p>唯一索引的作用:比如,当我们爬取数据时,如果使用了唯一索引,那么,当我们爬到重复数据时,就不会存储到数据库中</p></li> <li><p>默认有一个index:_id</p></li> <li><p>查看索引:db.集合.getIndex()</p></li> <li><p>删除索引:db.集合.dropIndex("索引名称") #索引名称即我们创建索引时传入的字典{属性:1或-1},可以通过getIndex()查看时的key项</p></li> </ul> <h2>爬虫数据去重,实现增量式爬虫</h2> <ul> <li><p>使用数据库建立唯一索引进行去重</p></li> <li> <p>url地址去重</p> <ul> <li> <p>使用场景</p> <ul> <li>如果url对应的数据不会变,url地址能够唯一的判别一条数据的情况</li> </ul> </li> <li> <p>思路</p> <ul> <li>url地址存在redis中</li> <li>拿到url地址,判断url地址在url的集合中是否存在</li> <li>存在:不再请求</li> <li>不存在:请求,并将该url地址存储到redis数据库中</li> </ul> </li> <li> <p>布隆过滤器</p> <ul> <li>使用加密算法加密url地址,得到多个值</li> <li>往对应值的位置把结果设置为1</li> <li>新来一个url地址,一样通过加密算法生成多个值</li> <li>如果对应位置的值全为1,说明这个url已经被抓过</li> <li>否则没有被抓过,就把对应位置的值设置为1</li> </ul> </li> </ul> </li> <li> <p>根据数据本身去重</p> <ul> <li>选择特定字段,使用加密算法(md5,shal)将字段进行加密,生成字符串,存入redis集合中</li> <li>如果新来一条数据,同样的方法进行加密,如果得到的数据在redis中存在,说明数据存在,要么插入,要么更新,否则不存在,直接插入</li> </ul> </li> </ul> <h2>数据的备份与恢复</h2> <p><strong>备份的语法</strong>:<br> mongodump -h dbhost -d dbname -o dbdirectory<br> -h: 服务器地址, 也可以指定端⼝号,如果是本机上,就可以省略<br> -d: 需要备份的数据库名称<br> -o: 备份的数据存放位置, 此⽬录中存放着备份出来的数据</p> <p>备份的数据中,一个json和一个bson表示一个集合</p> <p><strong>恢复的语法</strong>:<br> mongorestore -h dbhost -d dbname --dir dbdirectory<br> -h: 服务器地址<br> -d: 需要恢复的数据库实例,即数据库的名字<br> --dir: 备份数据所在位置</p> <hr> <h1>pymongo的使用</h1> <p>pip install pymongo<br> from pymongo import MongoClient</p> <p><strong>用法示例</strong></p> <pre><code class="python">from pymongo import MongoClient client = MongoClient(host='127.0.0.1',port=27017) #实例化client,即和数据库建立连接 collection = client['admin']['Temp'] #使用[]选择数据库和集合 collection.insert_one({"name":"laowang","age":33}) #插入一条数据 it_data = [{"name":"laoli","age":23},{"name":"laozhao","age":43}] collection.insert_many(it_data) #插入多条数据 print(collection.find_one({"name":"laoli"})) print(collection.find()) #是一个Cursor(游标)对象,一个Cursor对象只能进行一次遍历 for ret in collection.find(): print(ret) #遍历查看cursor对象 print(list(collection.find())) #强制转化为list collection.delete_one({"name":"laoli"}) #删除一个 collection.delete_many({"age":33}) #删除所有age为33的 # mongodb不需要我们手动断开连接 </code></pre> <hr> <h1>scrapy</h1> <h2>scrapy简介</h2> <p>为什么要使用scrapy:使我们的爬虫更快更强</p> <p>scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架</p> <p>scrapy使用了Twisted异步网络框架,可以加快我们的下载</p> <p><strong>scrapy的工作流程</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 489px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/a7bae3fdd4634317ab693f0617191b7e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/a7bae3fdd4634317ab693f0617191b7e.jpg" width="650" height="384" alt="Python67-爬虫_第23张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <p>scheduler里面实际上存放的并不是url地址,而是request对象</p> <p>在spiders处,url要先组装成request对象再交到scheduler调度器</p> <p>scrapy引擎的作用:scheduler将request交给scrapy engine,engine再交给下载器,response也是先由下载器交给scrapy engine,然后再由engine交给spiders,url类似,先交给scrapy engine,再交给scheduler</p> <p>engine实现了程序的解耦,response和request在经过scrapy后,还要经过各自的middleware,再交到目的地,因此我们就可以定义自己的中间件,对reponse和request进行一些额外的处理</p> <p>爬虫中间件不会对爬虫提取的数据进行数据(实际上可以,但是因为有专门的部分进行这项工作,所以我们通常不这么做)</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 466px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/0c294bb5d151422cb3b53d774bd984fc.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/0c294bb5d151422cb3b53d774bd984fc.jpg" width="650" height="418" alt="Python67-爬虫_第24张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>scrapy入门</h2> <ul> <li> <p>创建一 个scrapy项目:scrapy startproject 项目名(eg:myspider)</p> <br> <div class="image-package"> <div class="image-container" style="max-width: 555px; max-height: 376px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/6a31b37649c6424a84a93d86c984c6ce.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/6a31b37649c6424a84a93d86c984c6ce.jpg" width="555" height="376" alt="Python67-爬虫_第25张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> </li> <li><p>生成一个爬虫:scrapy genspider 爬虫名字 "允许爬取的域名"</p></li> <li> <p>提取数据</p> <ul> <li>完善spider,使用xpath等方法</li> </ul> </li> <li> <p>保存数据</p> <ul> <li>pipline中保存数据</li> </ul> </li> </ul> <h2>scrapy具体流程及spider和pipline讲解</h2> <p>此处的项目名为mySpider,创建的爬虫名字为itcast</p> <ul> <li><p>新建一个python项目</p></li> <li><p>在Terminal中:scrapy startproject mySpider</p></li> <li><p>在Terminal中,根据提示:cd mySpider</p></li> <li> <p>在Terminal中:scrapy genspider itcast "itcast.cn",此时,如果创建成功,就会在spiders目录中有了itcast.py;在里面,我们写上如下代码段内容:</p> <ul> <li> <p>在项目文件夹中使用scrapy新建的爬虫都在spider文件夹中,每个spider文件即对应上面流程图中的spiders,其中有几个默认字段:</p> <ul> <li>name:爬虫的名字,默认有</li> <li>allowed_domains:默认有(在使用scrapy新建spider的时候通常会指定)</li> <li>start_urls:默认有,但是通常需要我们自己修改,其值为我们最开始请求的url地址</li> <li>parse方法:处理start_url对应的响应地址,通过yield将我们提取到的数据传递到pipline</li> </ul> </li> </ul> <pre><code class="python">import scrapy class ItcastSpider(scrapy.Spider): name = 'itcast' #爬虫名 allowed_domains = ['itcast.cn'] #允许爬取的范围 start_urls = ['http://www.itcast.cn/channel/teacher.shtml'] #最开始请求的url地址 def parse(self, response): """处理start_url对应的响应""" # ret1 = respnse.xpath("//div[@class='tea_con']//h3/text()").extract() # #提取数据 # #extract()方法可以提取其中的文字 # print(ret1) li_list = response.xpath("//div[@class='tea_con']//li") for li in li_list: item = {} item['name'] = li.xpath(".//h3/text()").extract_first() #提取第一个字符串 #使用extract_first,如果是没有拿到元素,会返回none,而不是报错(extract()[0]在拿不到元素的情况下会报错) item['title'] = li.xpath(".//h4/text()").extract_first() yield item #将item传给piplines </code></pre> </li> <li><p>在Terminal中,进入项目文件夹下:scrapy crawl itcast,就会自动开始爬取;然后在terminal中输出一些结果和一些日志,我们可以在settings.py中对日志的级别进行设置,比如添加:LOG_LEVEL = "WARNING",比warning等级小的日志都不会输出</p></li> <li> <p>pipline的使用</p> <ul> <li><p>pipline对应流程图中的item pipline</p></li> <li> <p>要使用pipline,需要在项目的settings.py文件中取消对pipline的注释,使其可用,即</p> <pre><code class="python"># Configure item pipelines # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { 'mySpider.pipelines.MyspiderPipeline': 300, #意为:mySpider项目下的piplines模块中的MyspiderPipline类,后面的数字(300)表示距离引擎的远近,越近,数据就会越先经过该pipline #所谓管道,就是把前面管道处理后的数据再交给后面的管道处理,这里ITEM_PIPLINES的格式为字典:管道类的位置:距离引擎的远近 #把spiders提取的数据由近及远交给各个管道处理 #亦即:我们可以在piplines中定义自己的多个管道,然后在这里进行注册,使其可用,如下 'mySpider.pipelines.MyspiderPipeline1': 301, } </code></pre> </li> </ul> </li> <li><p>执行爬虫爬取数据:scrapy crawl 爬虫的名字(类下面的name的值)</p></li> <li> <p>在piplines.py中,我们定义了如下的两个管道</p> <ul> <li>为了让数据能够在各个管道间进行传递,每个管道必须return item,这里的item即为spider中传递过来的数据</li> <li>process_item方法是必须的,专门用于对数据的处理,只有它可以接受传递过来的item</li> <li>spider就是爬虫在传item的时候,把自己也传递过来了,即:这里的参数spider就是我们在spiders目录下的爬虫名的py文件中定义的spider类</li> </ul> <pre><code class="python">class MyspiderPipeline(object): def process_item(self, item, spider): print(item) return item class MyspiderPipeline1(object): def process_item(self, item, spider): print(item.items()) return item </code></pre> </li> <li> <p>为什么需要有多个pipline</p> <ul> <li>一个项目通常有多个爬虫,而对于爬取的数据,我们通常要进行的处理不相同,因此就需要使用不同的pipline <ul> <li>此时需要对传过来的item进行判别,比如可以使用在item中添加某字段以判别(或者使用spider进行判别,比如:if spider.name == xxx),如果是我们要处理的数据才进行处理,否则传递给其他pipline</li> </ul> </li> <li>一个spider的内容可能要做不同的操作,比如存入不同的数据库中,我们就可以使用多个pipline分多步进行</li> </ul> </li> </ul> <h2>logging模块的使用</h2> <p>在settings.py文件中,可以添加字段:LOG_LEVEL="log等级",以控制当前爬虫的输出的log等级(大于)</p> <p>在spider中输出log的两种常用方法:</p> <ul> <li><p><code>import logging</code>,然后使用<code>logging.warning(要输出的信息)</code>,无法显示log来自哪个文件</p></li> <li> <p><code>impot logging</code>,然后<code>logger = logging.getLogger(__name__)</code>,使用<code>logger.warning(要输出的数据)</code>,此种方法可以输出日志来自哪个文件</p> <ul> <li>ps:我们实例化了一个logger之后,在其他的文件中如果要使用log,不必单独再去实例化一个对象,直接导入现有的logger即可</li> </ul> </li> </ul> <p>如果我们要想使log输出到文件中,而非terminal,则需要在settings.py中添加字段:LOG_FILE = "保存log的文件路径"</p> <p>如果要自定义log的格式,在使用logging前:logging.basicConfig(xxx),其中的xxx即我们要自定义的log格式<br> logging.basicConfig()示例:</p> <pre><code class="python">import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filemode='w') </code></pre> <pre><code class="python">"""basicConfig参数""" logging.basicConfig函数各参数: filename: 指定日志文件名 filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a' format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示: %(levelno)s: 打印日志级别的数值 %(levelname)s: 打印日志级别名称 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s: 打印当前执行程序名 %(funcName)s: 打印日志的当前函数 %(lineno)d: 打印日志的当前行号 %(asctime)s: 打印日志的时间 %(thread)d: 打印线程ID %(threadName)s: 打印线程名称 %(process)d: 打印进程ID %(message)s: 打印日志信息 datefmt: 指定时间格式,同time.strftime() level: 设置日志级别,默认为logging.WARNING stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略 </code></pre> <h2>翻页请求</h2> <ul> <li>在爬虫中,首先,获得下一页的url:<code>next_url = response.xpath("//a[text()='下一页']/@href").extract()</code>以获得下一页的url</li> <li>然后使用scrapy.Request构造一个request,同时指定回调函数</li> <li>在回调函数中,对于要pipline处理的数据,同样要yield <pre><code class="python">while next_url: yield scrapy.Request(next_url, callback=self.parse) #如果下一页数据的处理和当前页相同,那么回调函数就直接指定当前函数即可,如果处理方式,则另外定义一个函数进行回调即可;这里实际上也是实例化了一个request对象交给引擎 </code></pre> </li> </ul> <p><strong>scrapy.request的其他知识点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 260px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/16372277dc9d4f5487b70736ba4bee52.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/16372277dc9d4f5487b70736ba4bee52.jpg" width="650" height="200" alt="Python67-爬虫_第26张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>如图所示,在crapy中,cookies就不能再放到headers中去</li> <li>所谓解析函数,可以简单理解为回调函数,meta的格式为字典,在解析函数中获取该数据时:response.meta["键"]</li> </ul> <p><strong>设置user-agent</strong></p> <ul> <li>user-agent的使用:在项目的设置文件中找到对应项进行设置即可</li> </ul> <p><strong>案例(结合下面的item)</strong></p> <p>爬取阳光热线问政平台:</p> <pre><code class="python"># -*- coding: utf-8 -*- import scrapy from yangguang.items import YangguangItem class YgSpider(scrapy.Spider): name = 'yg' allowed_domains = ['sun0769.com'] start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0'] def parse(self, response): tr_list = response.xpath("//div[@class='greyframe']/table[2]/tr/td/table/tr") for tr in tr_list: item = YangguangItem() item['title'] = tr.xpath("./td[2]/a[@class='news14']/@title").extract_first() item['href'] = tr.xpath("./td[2]/a[@class='news14']/@href").extract_first() item['publish_data'] = tr.xpath("./td[last()]/text()").extract_first() yield scrapy.Request( item['href'], callback= self.parse_detail, meta={"item":item} ) next_url = response.xpath("//a[text()='>']/@href").extract_first() if next_url: yield scrapy.Request( next_url, callback=self.parse ) def parse_detail(self,response): """处理详情页""" item = response.meta['item'] item['content'] = response.xpath("//td[@class='txt16_3']//text()").extract_first() item['content_img'] = response.xpath("//td[@class='txt16_3']//img/@src").extract() yield item </code></pre> <h2>scrapy深入</h2> <h3>Items</h3> <p>使用流程:</p> <ul> <li> <p>先在items.py中写好我们要使用的字段,如图:</p> <br> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 165px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/bef838c1f24142179ed98ffc4a3c1e43.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/bef838c1f24142179ed98ffc4a3c1e43.jpg" width="650" height="141" alt="Python67-爬虫_第27张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>说明:就相当于我们定义了一个字典类,规定好了里面可以有的键,以后如果使用这个字典的实例时,发现想往里面存入未定义的键,程序就会报错</li> </ul> </li> <li><p>使用时,在spider中导入该类(这里是Myspideritem),然后用其实例化一个对象(当作字典使用即可)</p></li> <li> <p>然后通常是用这个字典存储我们提取的数据,然后把其在各个piplines间传递</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 261px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/679b437aadb0426ab5096b9d3e61812b.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/679b437aadb0426ab5096b9d3e61812b.jpg" width="650" height="214" alt="Python67-爬虫_第28张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> </li> <li><p><code>注意:</code>item对象不能直接插入mongodb(只是像字典,毕竟不是字典),可以强制将其转化为字典,然后存入即可</p></li> <li><p>ps:对不同爬虫爬取的数据,我们可以定义多个item类,然后在pipline中处理时,可以用isinstance判断是否为某个item类的实例,如果是,我们才处理</p></li> </ul> <h3>debug信息</h3> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 293px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/7f78b002167344aea775298c2f9bbf12.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/7f78b002167344aea775298c2f9bbf12.jpg" width="650" height="221" alt="Python67-爬虫_第29张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h3>scrapy shell</h3> <p>Scrapy shell是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath表达式</p> <p>使用方法:<br> scrapy shell http://www.itcast.cn/channel/teacher.shtml</p> <p>就会自动进入shell,在shell中进行一些操作,会自动提示<br> 然后就能得到response</p> <p>response:</p> <ul> <li>response.url:当前响应的url地址</li> <li>response.request.url:当前响应对应的请求的url地址</li> <li>response.headers:响应头</li> <li>response.body:响应体,也就是html代码,默认是byte类型</li> <li>response.requests.headers:当前响应的请求头</li> <li>response.xpath()</li> </ul> <p>spider:</p> <ul> <li>spider.name</li> <li>spider.log(log信息)</li> </ul> <h3>settings</h3> <p><strong>settings中的字段</strong></p> <p>默认已有字段:</p> <ul> <li>bot_name:项目名</li> <li>spider_modules:爬虫位置</li> <li>newspider_module:新建爬虫的位置</li> <li>user-agent:用户代理</li> <li>robotstxt_obey:是否遵守robot协议</li> <li>CONCURRENT_REQUESTS:并发请求的最大数量</li> <li>DOWNLOAD_DELAY:下载延迟</li> <li>CONCURRENT_REQUESTS_PER_DOMAIN:每个域名的最大并发请求数</li> <li>CONCURRENT_REQUESTS_PER_IP:每个代理ip的最大并发请求数</li> <li>COOKIES_ENABLED:是否开启cookies</li> <li>TELNETCONSOLE_ENABLED:是否启用teleconsole插件</li> <li>DEFAULT_REQUEST_HEADERS:默认请求头</li> <li>spider_midddleware:爬虫中间件</li> <li>downlowd_middleware:下载中间件</li> <li>EXTENSIONS:插件</li> <li>ITEM_PIPELINES:管道,其格式为:<code>管道的位置:权重</code> </li> <li>AUTOTHROTTLE_ENABLED:自动限速</li> <li>缓存的配置项</li> </ul> <p>可自己添加字段:</p> <ul> <li>LOG_LEVEL</li> </ul> <p>在其他位置中要使用配置中的数据:</p> <ol> <li>法一:直接导入settings模块使用</li> <li>如果是在spider中:可以直接用self.settings.get()或是self.settings[]以字典的形式存取相关数据</li> <li>如果是在pipline中,由于传过来了spider,就以spider.settings.get()或spider.settings[]存取</li> </ol> <h3>piplines</h3> <pre><code class="python">import json class myPipline(object): def open_spider(self,spider): """在爬虫开启的时候执行一次""" #比如实例化MongoClient pass def close_spider(self,spider): """在爬虫关闭的时候执行一次""" pass def process_item(self,item,spider): """对spider yield过来的数据进行处理""" pass return item """如果不return item,其他的pipline就无法获得该数据""" </code></pre> <h2>CrawlSpider</h2> <p>之前爬虫的思路:<br> 1、从response中提取所有的a标签对应的url地址<br> 2、自动的构造自己requests请求,发送给引擎</p> <p>改进:</p> <p>满足某个条件的url地址,我们才发送给引擎,同时能够指定callback函数</p> <p>如何生成crawlspider:<br> eg:<br> scrapy genspider –t crawl csdn “csdn.com"</p> <p>crawlspider示例:</p> <pre><code class="python">from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule import re class CfSpider(CrawlSpider): #继承的父类不再是scrapy.spider name = 'cf' allowed_domains = ['circ.gov.cn'] start_urls = ['http://circ.gov.cn/web/site0/tab5240/module14430/page1.htm'] """定义提取url规则的地方""" """每个Rule是一个元组""" """注意:每个url提取出来后被构造成一个请求,他们没有先后顺序""" rules = ( #Rule是一个类,LinkExtractor: 链接提取器,其参数是一个正则表达式,提取到了link,就交给parse函数进行请求 #所以我们在crawlspider中不能自己定义parse函数 #url请求的响应数据会交给callback处理,如果不用提取该url中的数据,就可以不指定callback #follow,当前url地址的相应是否重新进入rules来提取url地址(会挨个按规则提取,如果被前面的正则表达式匹配到了,就不会再被后面的进行匹配提取,所以写正则表达式的时候应该尽可能明确) #注意:crawlspider能够帮助我们自动把链接补充完整,所以我们下面的allow中并没有手动补全链接 Rule(LinkExtractor(allow=r'/web/site0/tab5240/info\d+.htm'), callback='parse_item', follow=False), Rule(LinkExtractor(allow=r'/web/site0/tab5240/module14430/page\d+.htm'), follow=True), ) """parse函数不见了,因为其有特殊功能,不能定义""" def parse_item(self, response): """解析函数""" item = {} #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get() #item['name'] = response.xpath('//div[@id="name"]').get() #item['description'] = response.xpath('//div[@id="description"]').get() item['title'] = re.findall(r"<!--TitleStart-->(.*?)<!--TitleEnd-->",response.body.decode())[0] item['date'] = re.findall(r"发布时间:(\d{4}-\d{2}-\d{2})",response.body.decode()) print(item) # 也可以自己再yiel scrapy.Request # yield scrapy.Request( # url, # callback=self.parse_detail, # meta={"item":item} # ) # # def parse_detail(self,response): # item = response.meta['item'] # pass # yield item </code></pre> <p><strong>LinkExtractor和Rule的更多知识点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 471px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/89ea9a72f7c64202a9e4cee3dd83097f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/89ea9a72f7c64202a9e4cee3dd83097f.jpg" width="650" height="410" alt="Python67-爬虫_第30张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>中间件</h2> <h3>下载中间件</h3> <p>下载中间件是我们要经常操作的一个中间件,因为我们常常需要在下载中间件中对请求和响应做一些自定义的处理</p> <p>如果我们要使用中间件,需要在settings中开启,其格式也是:位置:权重(或者说是距离引擎的位置,越小越先经过)</p> <p><strong>Downloader Middlewares默认的方法</strong>:</p> <ul> <li>process_request(self, request, spider):<br> 当每个request通过下载中间件时,该方法被调用。</li> <li>process_response(self, request, response, spider):<br> 当下载器完成http请求,传递响应给引擎的时候调用</li> </ul> <p>案例:使用随机user-agent:</p> <p>在settings.py中定义USER_AGENTS_LIST:</p> <pre><code class="python">USER_AGENTS_LIST = ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0', ] </code></pre> <p>在middlewares.py中定义下载中间件:</p> <pre><code class="python">import random class RandomUserAgentMiddleware: """自定义一个下载中间件""" def process_request(self,request,spider): ua = random.choice(spider.settings.get("USER_AGENTS_LIST")) request.headers["User-Agent"] = ua #request.meta['proxy'] = "你的proxy" #也可以通过此种方法来使用代理 # return request,process不能返回request class CheckUserAgentMiddleware: def process_response(selfs,request,response,spider): print(request.headers["User-Agent"]) #查看是否实现了随机用户代理 return response # process_response必须返回reponse </code></pre> <p>并在settings.py中对自己的中间件进行注册:</p> <pre><code class="python">DOWNLOADER_MIDDLEWARES = { # 'circ.middlewares.CircDownloaderMiddleware': 543, 'circ.middlewares.RandomUserAgentMiddleware': 544, 'circ.middlewares.CheckUserAgentMiddleware': 545, #这里的权重并不重要,因为他们一个是处理请求,一个是处理响应的 } </code></pre> <p>spiders内容省略</p> <h2>scrapy模拟登录</h2> <p>对于scrapy来说,有两个方法模拟登陆:<br> 1、直接携带cookie<br> 2、找到发送post请求的url地址,带上信息,发送请求</p> <h3>直接携带cookie</h3> <p>案例:爬取人人网登录后的信息</p> <pre><code class="python">import scrapy import re class RenrenSpider(scrapy.Spider): name = 'renren' allowed_domains = ['renren.com'] start_urls = ['http://www.renren.com/971962231/profile'] #人人网的个人主页 def start_requests(self): """覆盖父类的start_request方法,从而使其携带我们自己的cookies""" cookies = "我的cookies" cookies = {i.split("=")[0]:i.split("=")[1] for i in cookies.split(";")} yield scrapy.Request( self.start_urls[0], callback=self.parse, #表示当前请求的响应会发送到parse cookies=cookies ) #因为cookies默认是enable的,所以下次请求会自动拿到上次的cookies def parse(self, response): print(re.findall(r"假装",response.body.decode())) #验证是否请求成功 yield scrapy.Request( "http://www.renren.com/971962231/profile?v=info_timeline", callback=self.parse_data, ) def parse_data(self,response): """"访问个人资料页,验证cookie的传递""" print(re.findall(r"学校信息",response.body.decode())) </code></pre> <p>此外,为了查看cookies的传递过程,可以在settings中加上字段:COOKIES_DEBUG = True</p> <h3>scrapy发送post请求</h3> <p>案例:爬取github</p> <p>spider:</p> <pre><code class="python">import scrapy import re class GitSpider(scrapy.Spider): name = 'git' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first() utf8 = response.xpath("//input[@name='utf8']/@value").extract_first() webauthn_support = response.xpath("//input[@name='webauthn-support']/@value").extract_first() post_data = { "login":"你的邮箱", "password":"密码", "webauthn-support":webauthn_support, "authenticity_token":authenticity_token, "utf8":utf8 } print(post_data) yield scrapy.FormRequest( "https://github.com/session", #数据提交到的地址 formdata=post_data, callback=self.after_login #无论这个post请求成功没有,响应都会交给after_login ) def after_login(self,response): print(response) print(re.findall(r"Trial_Repo", response.body.decode())) #匹配我的某个仓库名,以验证是否成功 </code></pre> <p>settings中的修改字段:</p> <pre><code class="python">USER_AGENT = 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36' ROBOTSTXT_OBEY = False </code></pre> <p><strong>scrapy还可以帮我们自动从表单中提取action的地址</strong></p> <p>爬取github登录后的页面:<br> spider:</p> <pre><code class="python"># -*- coding: utf-8 -*- import scrapy import re class Github2Spider(scrapy.Spider): name = 'github2' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): post_data = { "login":"2537119279@qq.com", "password":"A1d9b961017#" } yield scrapy.FormRequest.from_response( #自动从response中寻找form表单,然后将formdata提交到对应的action的url地址 #如果有多个form表单,可以通过其他参数对表单进行定位,其他参数见源码 response, formdata=post_data, callback=self.after_login, ) def after_login(self,response): print(re.findall(r"Trial_Repo", response.body.decode())) </code></pre> <p>另:无需在settings中设置任何东西</p> <hr> <h1>scrapy_redis</h1> <ul> <li>scrapy_redis的作用:reqeust去重,爬虫持久化,和轻松实现分布式</li> </ul> <p><strong>scrapy_redis爬虫的流程</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 613px; max-height: 470px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9e20adf1996b43de84ab2f777ce5ee0e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9e20adf1996b43de84ab2f777ce5ee0e.jpg" width="613" height="470" alt="Python67-爬虫_第31张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <p>上图中的指纹是指request指纹,指纹能够唯一标识一个request,从而避免重复的reqeust请求</p> <p>所以redis中常存储待爬的request对象和已爬取的request的指纹</p> <p><strong>redis基础</strong></p> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 594px; max-height: 224px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/d876178d36524198b7e66f8b4b6e67d6.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/d876178d36524198b7e66f8b4b6e67d6.jpg" width="594" height="224" alt="Python67-爬虫_第32张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> scrapy_redis的地址: https://github.com/rmax/scrapy-redis <p></p> </article> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1408112466889637888"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Python67-爬虫)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835490218845761536.htm" title="Python爬虫解析工具之xpath使用详解" target="_blank">Python爬虫解析工具之xpath使用详解</a> <span class="text-muted">eqa11</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>文章目录Python爬虫解析工具之xpath使用详解一、引言二、环境准备1、插件安装2、依赖库安装三、xpath语法详解1、路径表达式2、通配符3、谓语4、常用函数四、xpath在Python代码中的使用1、文档树的创建2、使用xpath表达式3、获取元素内容和属性五、总结Python爬虫解析工具之xpath使用详解一、引言在Python爬虫开发中,数据提取是一个至关重要的环节。xpath作为一门</div> </li> <li><a href="/article/1835483159630802944.htm" title="nosql数据库技术与应用知识点" target="_blank">nosql数据库技术与应用知识点</a> <span class="text-muted">皆过客,揽星河</span> <a class="tag" taget="_blank" href="/search/NoSQL/1.htm">NoSQL</a><a class="tag" taget="_blank" href="/search/nosql/1.htm">nosql</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">非关系型数据库</a> <div>Nosql知识回顾大数据处理流程数据采集(flume、爬虫、传感器)数据存储(本门课程NoSQL所处的阶段)Hdfs、MongoDB、HBase等数据清洗(入仓)Hive等数据处理、分析(Spark、Flink等)数据可视化数据挖掘、机器学习应用(Python、SparkMLlib等)大数据时代存储的挑战(三高)高并发(同一时间很多人访问)高扩展(要求随时根据需求扩展存储)高效率(要求读写速度快)</div> </li> <li><a href="/article/1835454921990828032.htm" title="Java爬虫框架(一)--架构设计" target="_blank">Java爬虫框架(一)--架构设计</a> <span class="text-muted">狼图腾-狼之传说</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E4%BB%BB%E5%8A%A1/1.htm">任务</a><a class="tag" taget="_blank" href="/search/html%E8%A7%A3%E6%9E%90%E5%99%A8/1.htm">html解析器</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E5%82%A8/1.htm">存储</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1/1.htm">电子商务</a> <div>一、架构图那里搜网络爬虫框架主要针对电子商务网站进行数据爬取,分析,存储,索引。爬虫:爬虫负责爬取,解析,处理电子商务网站的网页的内容数据库:存储商品信息索引:商品的全文搜索索引Task队列:需要爬取的网页列表Visited表:已经爬取过的网页列表爬虫监控平台:web平台可以启动,停止爬虫,管理爬虫,task队列,visited表。二、爬虫1.流程1)Scheduler启动爬虫器,TaskMast</div> </li> <li><a href="/article/1835454543471669248.htm" title="Java:爬虫框架" target="_blank">Java:爬虫框架</a> <span class="text-muted">dingcho</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>一、ApacheNutch2【参考地址】Nutch是一个开源Java实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。Nutch致力于让每个人能很容易,同时花费很少就可以配置世界一流的Web搜索引擎.为了完成这一宏伟的目标,Nutch必须能够做到:每个月取几十亿网页为这些网页维护一个索引对索引文件进行每秒上千次的搜索提供高质量的搜索结果简单来说Nutch支持分</div> </li> <li><a href="/article/1835438028009598976.htm" title="WebMagic:强大的Java爬虫框架解析与实战" target="_blank">WebMagic:强大的Java爬虫框架解析与实战</a> <span class="text-muted">Aaron_945</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>文章目录引言官网链接WebMagic原理概述基础使用1.添加依赖2.编写PageProcessor高级使用1.自定义Pipeline2.分布式抓取优点结论引言在大数据时代,网络爬虫作为数据收集的重要工具,扮演着不可或缺的角色。Java作为一门广泛使用的编程语言,在爬虫开发领域也有其独特的优势。WebMagic是一个开源的Java爬虫框架,它提供了简单灵活的API,支持多线程、分布式抓取,以及丰富的</div> </li> <li><a href="/article/1835435506645692416.htm" title="00. 这里整理了最全的爬虫框架(Java + Python)" target="_blank">00. 这里整理了最全的爬虫框架(Java + Python)</a> <span class="text-muted">有一只柴犬</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB%E7%B3%BB%E5%88%97/1.htm">爬虫系列</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>目录1、前言2、什么是网络爬虫3、常见的爬虫框架3.1、java框架3.1.1、WebMagic3.1.2、Jsoup3.1.3、HttpClient3.1.4、Crawler4j3.1.5、HtmlUnit3.1.6、Selenium3.2、Python框架3.2.1、Scrapy3.2.2、BeautifulSoup+Requests3.2.3、Selenium3.2.4、PyQuery3.2</div> </li> <li><a href="/article/1835412560413814784.htm" title="python爬取微信小程序数据,python爬取小程序数据" target="_blank">python爬取微信小程序数据,python爬取小程序数据</a> <span class="text-muted">2301_81900439</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>大家好,小编来为大家解答以下问题,python爬取微信小程序数据,python爬取小程序数据,现在让我们一起来看看吧!Python爬虫系列之微信小程序实战基于Scrapy爬虫框架实现对微信小程序数据的爬取首先,你得需要安装抓包工具,这里推荐使用Charles,至于怎么使用后期有时间我会出一个事例最重要的步骤之一就是分析接口,理清楚每一个接口功能,然后连接起来形成接口串思路,再通过Spider的回调</div> </li> <li><a href="/article/1835347005522669568.htm" title="大模型训练数据库Common Crawl" target="_blank">大模型训练数据库Common Crawl</a> <span class="text-muted">WindyChanChan</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E9%9B%86/1.htm">数据集</a><a class="tag" taget="_blank" href="/search/%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B/1.htm">语言模型</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>CommonCrawl介绍‌‌CommonCrawl是一个非营利组织,致力于通过大规模分布式爬虫系统定期抓取整个Web并将其存储在一个可公开访问的数据库中。CommonCrawl的数据收集和处理过程包括使用Python开源爬虫工具收集全球范围内的网站数据,并将其上传到‌CommonCrawl基金会的数据仓库中。该项目从2008年开始,至今已经积累了大量的原始网页数据、元数据和文本提取数据。这些数据</div> </li> <li><a href="/article/1835342718067372032.htm" title="Python精选200Tips:121-125" target="_blank">Python精选200Tips:121-125</a> <span class="text-muted">AnFany</span> <a class="tag" taget="_blank" href="/search/Python200%2BTips/1.htm">Python200+Tips</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>Spendyourtimeonself-improvement121Requests-简化的HTTP请求处理发送GET请求发送POST请求发送PUT请求发送DELETE请求会话管理处理超时文件上传122BeautifulSoup-网页解析和抓取解析HTML和XML文档查找单个标签查找多个标签使用CSS选择器查找标签提取文本修改文档内容删除标签处理XML文档123Scrapy-强大的网络爬虫框架示例</div> </li> <li><a href="/article/1835333520919195648.htm" title="爬虫技术抓取网站数据被限制怎么处理" target="_blank">爬虫技术抓取网站数据被限制怎么处理</a> <span class="text-muted">Bearjumpingcandy</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>爬虫技术用于抓取网站数据时,可能会遇到一些限制,常见的包括反爬机制、速率限制、IP封禁等。以下是应对这些情况的一些策略:尊重robots.txt:每个网站都有robots.txt文件,遵循其中的规定可以避免触犯网站的抓取规则。设置合理频率:控制爬虫请求的速度,通过添加延迟或使用代理服务器,减少对目标网站的压力。使用代理:获取并使用代理IP地址可以更换访问来源,降低被识别的可能性。模拟用户行为:使用</div> </li> <li><a href="/article/1835333267952332800.htm" title="网站推广爬虫" target="_blank">网站推广爬虫</a> <span class="text-muted">Bearjumpingcandy</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>网站推广爬虫是一种用于升网站曝光度和推广效果的工具。它通过自动化地访问和收集网站信息,从而实现对目标网站的广告、关键词、排名等数据进行分析和优化。以下是网站推广爬虫的一些介绍:数据收集:网站推广爬虫可以自动访问目标网站,并收集相关的数据,如网站流量、关键词排名、竞争对手信息等。这些数据可以帮助网站推广人员了解网站的现状和竞争环境,从而制定相应的推广策略。关键词优化:通过分析搜索引擎的关键词排名情况</div> </li> <li><a href="/article/1835333268375957504.htm" title="爬虫技术抓取网站数据" target="_blank">爬虫技术抓取网站数据</a> <span class="text-muted">Bearjumpingcandy</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>爬虫技术是一种自动化获取网站数据的技术,它可以模拟人类浏览器的行为,访问网页并提取所需的信息。以下是爬虫技术抓取网站数据的一般步骤:发起HTTP请求:爬虫首先会发送HTTP请求到目标网站,获取网页的内容。解析HTML:获取到网页内容后,爬虫会使用HTML解析器解析HTML代码,提取出需要的数据。数据提取:通过使用XPath、CSS选择器或正则表达式等工具,爬虫可以从HTML中提取出所需的数据,如文</div> </li> <li><a href="/article/1835333268858302464.htm" title="爬虫技术抓取网站数据" target="_blank">爬虫技术抓取网站数据</a> <span class="text-muted">Bearjumpingcandy</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>爬虫技术是指通过程序自动访问网页并提取数据的技术。一般来说,爬虫技术包含以下几个步骤:确定目标网站:确定需要抓取的网站,并了解其页面结构和数据特点。分析页面结构:分析网页的结构和源代码,找到需要抓取的数据在页面中的位置和标识。编写爬虫程序:使用编程语言(如Python)编写爬虫程序,实现对目标网站的自动访问和数据提取。处理抓取数据:对抓取到的数据进行清洗、去重、整合等处理,以便后续的分析和利用。爬</div> </li> <li><a href="/article/1835332888674004992.htm" title="爬虫之隧道代理:如何在爬虫中使用代理IP?" target="_blank">爬虫之隧道代理:如何在爬虫中使用代理IP?</a> <span class="text-muted">2401_87251497</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/tcp%2Fip/1.htm">tcp/ip</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/1.htm">网络协议</a> <div>在进行网络爬虫时,使用代理IP是一种常见的方式来绕过网站的反爬虫机制,提高爬取效率和数据质量。本文将详细介绍如何在爬虫中使用隧道代理,包括其原理、优势以及具体的实现方法。无论您是爬虫新手还是有经验的开发者,这篇文章都将为您提供实用的指导。什么是隧道代理?隧道代理是一种高级的代理技术,它通过创建一个加密的隧道,将数据从客户端传输到代理服务器,再由代理服务器转发到目标服务器。这样不仅可以隐藏客户端的真</div> </li> <li><a href="/article/1835288964056051712.htm" title="分享一个基于python的电子书数据采集与可视化分析 hadoop电子书数据分析与推荐系统 spark大数据毕设项目(源码、调试、LW、开题、PPT)" target="_blank">分享一个基于python的电子书数据采集与可视化分析 hadoop电子书数据分析与推荐系统 spark大数据毕设项目(源码、调试、LW、开题、PPT)</a> <span class="text-muted">计算机源码社</span> <a class="tag" taget="_blank" href="/search/Python%E9%A1%B9%E7%9B%AE/1.htm">Python项目</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E9%80%89%E9%A2%98/1.htm">计算机毕业设计选题</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E6%BA%90%E7%A0%81/1.htm">计算机毕业设计源码</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/spark%E6%AF%95%E8%AE%BE/1.htm">spark毕设</a> <div>作者:计算机源码社个人简介:本人八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!学习资料、程序开发、技术解答、文档报告如需要源码,可以扫取文章下方二维码联系咨询Java项目微信小程序项目Android项目Python项目PHP项目ASP.NET项目Node.js项目选题推荐项目实战|p</div> </li> <li><a href="/article/1835270188086423552.htm" title="python抓取网页内容401应该用哪个库_python3使用requests模块爬取页面内容入门" target="_blank">python抓取网页内容401应该用哪个库_python3使用requests模块爬取页面内容入门</a> <span class="text-muted">坂田月半</span> <div>python的爬虫相关模块有很多,除了requests模块,再如urllib和pycurl以及tornado等。相比而言,requests模块是相对简单易上手的。通过文本,大家可以迅速学会使用python的requests模块爬取页码内容。1.Requests唯一的一个非转基因的PythonHTTP库,人类可以安全享用。官网:http://cn.python-requests.org/zh_CN/</div> </li> <li><a href="/article/1835257575277424640.htm" title="【Python爬虫】百度百科词条内容" target="_blank">【Python爬虫】百度百科词条内容</a> <span class="text-muted">PokiFighting</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/1.htm">数据处理</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>词条内容我这里随便选取了一个链接,用的是FBI的词条importurllib.requestimporturllib.parsefromlxmlimportetreedefquery(url):headers={'user-agent':'Mozilla/5.0(WindowsNT6.1;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.</div> </li> <li><a href="/article/1835253670858551296.htm" title="爬虫和代理IP的关系" target="_blank">爬虫和代理IP的关系</a> <span class="text-muted">xiaoxiongip666</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/tcp%2Fip/1.htm">tcp/ip</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a> <div>爬虫和代理IP之间的关系是相互依存的。代理IP为爬虫提供了绕过IP限制、隐藏真实IP、提高访问速度等能力,使得爬虫能够更有效地进行数据抓取。然而,在使用时也需要注意合法性、稳定性、成本以及隐私保护等问题。</div> </li> <li><a href="/article/1835219887434330112.htm" title="python语言爬虫爬取歌曲程序代码" target="_blank">python语言爬虫爬取歌曲程序代码</a> <span class="text-muted">EYYLTV</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>importrequestssong_urls=[“http://music.163.com/song/media/outer/url?id=25795016.mp3”,“https://m703.music.126.net/20240915140140/670dfe5c0144991d4cb778d6662fd762/jd-musicrep-privatecloud-audio-public/o</div> </li> <li><a href="/article/1835219887958618112.htm" title="python语言爬虫爬取歌曲代码X" target="_blank">python语言爬虫爬取歌曲代码X</a> <span class="text-muted">EYYLTV</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>importrequestssong_urls=[“https://m804.music.126.net/20240915142147/4e01caa69abda60b165e185607805ee1/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/30379084686/b56a/dbd5/39fc/792d87f5d7014bb78547ec3804eeaac5.m4a?au</div> </li> <li><a href="/article/1835198462984024064.htm" title="拼多多商家电话采集工具 爬虫教程分享" target="_blank">拼多多商家电话采集工具 爬虫教程分享</a> <span class="text-muted">小电商达人</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>以下是使用Python编写的拼多多商家电话采集爬虫教程:一、前期准备安装Python:从Python官方网站下载并安装最新版本的Python,安装过程中注意勾选将Python添加到系统路径选项。安装相关库:在命令提示符中运行以下命令来安装所需的库。pipinstallrequests:用于发送HTTP请求获取网页内容。pipinstallbeautifulsoup4:用于解析HTML页面。二、分析</div> </li> <li><a href="/article/1835157319500001280.htm" title="Python爬虫代理池" target="_blank">Python爬虫代理池</a> <span class="text-muted">极客李华</span> <a class="tag" taget="_blank" href="/search/python%E6%8E%88%E8%AF%BE/1.htm">python授课</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>Python爬虫代理池网络爬虫在数据采集和信息抓取方面起到了关键作用。然而,为了应对网站的反爬虫机制和保护爬虫的真实身份,使用代理池变得至关重要。1.代理池的基本概念:代理池是一组包含多个代理IP地址的集合。通过在爬虫中使用代理池,我们能够隐藏爬虫的真实IP地址,实现一定程度的匿名性。这有助于防止被目标网站封锁或限制访问频率。2.为何使用代理池:匿名性:代理池允许爬虫在请求目标网站时使用不同的IP</div> </li> <li><a href="/article/1835143079305244672.htm" title="大数据毕业设计hadoop+spark+hive知识图谱租房数据分析可视化大屏 租房推荐系统 58同城租房爬虫 房源推荐系统 房价预测系统 计算机毕业设计 机器学习 深度学习 人工智能" target="_blank">大数据毕业设计hadoop+spark+hive知识图谱租房数据分析可视化大屏 租房推荐系统 58同城租房爬虫 房源推荐系统 房价预测系统 计算机毕业设计 机器学习 深度学习 人工智能</a> <span class="text-muted">2401_84572577</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>做了那么多年开发,自学了很多门编程语言,我很明白学习资源对于学一门新语言的重要性,这些年也收藏了不少的Python干货,对我来说这些东西确实已经用不到了,但对于准备自学Python的人来说,或许它就是一个宝藏,可以给你省去很多的时间和精力。别在网上瞎学了,我最近也做了一些资源的更新,只要你是我的粉丝,这期福利你都可拿走。我先来介绍一下这些东西怎么用,文末抱走。(1)Python所有方向的学习路线(</div> </li> <li><a href="/article/1835067814621310976.htm" title="10个高效的Python爬虫框架,你用过几个?" target="_blank">10个高效的Python爬虫框架,你用过几个?</a> <span class="text-muted">进击的C语言</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapyscrapy官网:https://scrapy.org/scrapy中文文档:https://www.osgeo.cn/scrapy/intro/oScrapy是一个为了爬取网站数据,提取结构性数据而编写的</div> </li> <li><a href="/article/1835007168928116736.htm" title="python爬虫(5)之CSDN" target="_blank">python爬虫(5)之CSDN</a> <span class="text-muted">It is a deal️</span> <a class="tag" taget="_blank" href="/search/%E5%B0%8F%E9%A1%B9%E7%9B%AE/1.htm">小项目</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>CSDN的爬虫相对于doubatop250更加简单,一般只需要title和url即可下面是相关的代码:#爬虫之csdn#分析urlhttps://www.csdn.net/api/articles?type=more&category=python&shown_offset=0(firstpage)#https://www.csdn.net/api/articles?type=more&categ</div> </li> <li><a href="/article/1835005152646492160.htm" title="python学习第七节:正则表达式" target="_blank">python学习第七节:正则表达式</a> <span class="text-muted">一只会敲代码的小灰灰</span> <a class="tag" taget="_blank" href="/search/python%E5%AD%A6%E4%B9%A0/1.htm">python学习</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a> <div>python学习第七节:正则表达式正则表达式基本上在所有开发语言中都会使用到,在python中尤为重要。当我们使用python开发爬虫程序将目标网页扒下来之后我们要从网页中解析出我们想要的信息,这个时候就需要正则表达式去进行匹配。importrere的常量re模块中有9个常量,常量的值都是int类型!(知道就行)修饰符描述re.l使匹配对大小写不敏感re.L做本地化识别(locale-aware)</div> </li> <li><a href="/article/1834965554214039552.htm" title="分布式框架Celery七(Django-Celery-Flower实现异步和定时爬虫及其监控邮件告警)" target="_blank">分布式框架Celery七(Django-Celery-Flower实现异步和定时爬虫及其监控邮件告警)</a> <span class="text-muted">yjjpp2301</span> <a class="tag" taget="_blank" href="/search/Celery/1.htm">Celery</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>Django中集成方式安装模块pipinstallDjango==3.2.22pipinstallcelerypipinstallredispipinstalleventlet#在windows环境下需要安装eventlet包-----------pipinstalldjango-celery-beatpipinstalldjango-celery-resultspipinstalldjango-</div> </li> <li><a href="/article/1834960888273137664.htm" title="生产者消费者模式_Labview基础之生产者消费者设计模式(事件)" target="_blank">生产者消费者模式_Labview基础之生产者消费者设计模式(事件)</a> <span class="text-muted">weixin_39532699</span> <a class="tag" taget="_blank" href="/search/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F/1.htm">生产者消费者模式</a> <div>1绪论近期,开了一个QQ群,刚开始的目的也是想多拉写软件相关的大神,有问题的时候也可以交流交流。记得当时有个软件在写的时候遇到了一个棘手的问题,outlook邮箱配置账户密码的问题,到现在也没解决,算了,也不是很迫切。2000人群就留在那里爬虫发单吧!建群以后才发现,原来这一块的小白还挺多,总结起来就一个原因:做这个软件的大多数都不是软件出生,都是因为临时要搭建一个上位机平台,匆匆入门......</div> </li> <li><a href="/article/1834943236649611264.htm" title="Python——爬虫" target="_blank">Python——爬虫</a> <span class="text-muted">星和月</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>当编写一个Python爬虫时,你可以使用BeautifulSoup库来解析网页内容,使用requests库来获取网页的HTML代码。下面是一个简单的示例,演示了如何获取并解析网页内容:importrequestsfrombs4importBeautifulSoup#发送HTTP请求获取网页内容url='https://www.example.com'#要爬取的网页的URLresponse=requ</div> </li> <li><a href="/article/1834807218839580672.htm" title="Python数据分析之股票信息可视化实现matplotlib" target="_blank">Python数据分析之股票信息可视化实现matplotlib</a> <span class="text-muted">Blogfish</span> <a class="tag" taget="_blank" href="/search/Python3/1.htm">Python3</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%8F%AF%E8%A7%86%E5%8C%96/1.htm">可视化</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>今天学习爬虫技术数据分析对于股票信息的分析及结果呈现,目标是实现对股票信息的爬取并对数据整理后,生成近期成交量折线图。首先,做这个案例一定要有一个明确的思路。知道要干啥,知道用哪些知识,有些方法我也记不住百度下知识库很强大,肯定有答案。有思路以后准备对数据处理,就是几个方法使用了。接口地址参考:Tushare数据涉及知识库:tushare-一个财经数据开放接口;pandas-实现将数据整理为表格,</div> </li> <li><a href="/article/39.htm" title="java Illegal overloaded getter method with ambiguous type for propert的解决" target="_blank">java Illegal overloaded getter method with ambiguous type for propert的解决</a> <span class="text-muted">zwllxs</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a> <div>好久不来iteye,今天又来看看,哈哈,今天碰到在编码时,反射中会抛出 Illegal overloaded getter method with ambiguous type for propert这么个东东,从字面意思看,是反射在获取getter时迷惑了,然后回想起java在boolean值在生成getter时,分别有is和getter,也许我们的反射对象中就有is开头的方法迷惑了jdk,</div> </li> <li><a href="/article/166.htm" title="IT人应当知道的10个行业小内幕" target="_blank">IT人应当知道的10个行业小内幕</a> <span class="text-muted">beijingjava</span> <a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/%E4%BA%92%E8%81%94%E7%BD%91/1.htm">互联网</a> <div>10. 虽然IT业的薪酬比其他很多行业要好,但有公司因此视你为其“佣人”。   尽管IT人士的薪水没有互联网泡沫之前要好,但和其他行业人士比较,IT人的薪资还算好点。在接下的几十年中,科技在商业和社会发展中所占分量会一直增加,所以我们完全有理由相信,IT专业人才的需求量也不会减少。   然而,正因为IT人士的薪水普遍较高,所以有些公司认为给了你这么多钱,就把你看成是公司的“佣人”,拥有你的支配</div> </li> <li><a href="/article/293.htm" title="java 实现自定义链表" target="_blank">java 实现自定义链表</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a> <div>1.链表结构   链表是链式的结构 2.链表的组成    链表是由头节点,中间节点和尾节点组成    节点是由两个部分组成:       1.数据域       2.引用域 3.链表的实现 &nbs</div> </li> <li><a href="/article/420.htm" title="web项目发布到服务器后图片过一会儿消失" target="_blank">web项目发布到服务器后图片过一会儿消失</a> <span class="text-muted">麦田的设计者</span> <a class="tag" taget="_blank" href="/search/struts2/1.htm">struts2</a><a class="tag" taget="_blank" href="/search/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87/1.htm">上传图片</a><a class="tag" taget="_blank" href="/search/%E6%B0%B8%E4%B9%85%E4%BF%9D%E5%AD%98/1.htm">永久保存</a> <div>  作为一名学习了android和j2ee的程序员,我们必须要意识到,客服端和服务器端的交互是很有必要的,比如你用eclipse写了一个web工程,并且发布到了服务器(tomcat)上,这时你在webapps目录下看到了你发布的web工程,你可以打开电脑的浏览器输入http://localhost:8080/工程/路径访问里面的资源。但是,有时你会突然的发现之前用struts2上传的图片</div> </li> <li><a href="/article/547.htm" title="CodeIgniter框架Cart类 name 不能设置中文的解决方法" target="_blank">CodeIgniter框架Cart类 name 不能设置中文的解决方法</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/CodeIgniter/1.htm">CodeIgniter</a><a class="tag" taget="_blank" href="/search/Cart/1.htm">Cart</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6%E3%80%80/1.htm">框架 </a> <div>今天试用了一下CodeIgniter的Cart类时遇到了个小问题,发现当name的值为中文时,就写入不了session。在这里特别提醒一下。 在CI手册里也有说明,如下: $data = array( 'id' => 'sku_123ABC', 'qty' => 1, '</div> </li> <li><a href="/article/674.htm" title="linux回收站" target="_blank">linux回收站</a> <span class="text-muted">_wy_</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%9B%9E%E6%94%B6%E7%AB%99/1.htm">回收站</a> <div>今天一不小心在ubuntu下把一个文件移动到了回收站,我并不想删,手误了。我急忙到Nautilus下的回收站中准备恢复它,但是里面居然什么都没有。     后来我发现这是由于我删文件的地方不在HOME所在的分区,而是在另一个独立的Linux分区下,这是我专门用于开发的分区。而我删除的东东在分区根目录下的.Trash-1000/file目录下,相关的删除信息(删除时间和文件所在</div> </li> <li><a href="/article/801.htm" title="jquery回到页面顶端" target="_blank">jquery回到页面顶端</a> <span class="text-muted">知了ing</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>html代码: <h1 id="anchor">页面标题</h1> <div id="container">页面内容</div> <p><a href="#anchor" class="topLink">回到顶端</a><</div> </li> <li><a href="/article/928.htm" title="B树、B-树、B+树、B*树" target="_blank">B树、B-树、B+树、B*树</a> <span class="text-muted">矮蛋蛋</span> <a class="tag" taget="_blank" href="/search/B%E6%A0%91/1.htm">B树</a> <div>原文地址: http://www.cnblogs.com/oldhorse/archive/2009/11/16/1604009.html B树        即二叉搜索树:        1.所有非叶子结点至多拥有两个儿子(Left和Right); &nb</div> </li> <li><a href="/article/1055.htm" title="数据库连接池" target="_blank">数据库连接池</a> <span class="text-muted">alafqq</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0/1.htm">数据库连接池</a> <div>http://www.cnblogs.com/xdp-gacl/p/4002804.html @Anthor:孤傲苍狼 数据库连接池 用MySQLv5版本的数据库驱动没有问题,使用MySQLv6和Oracle的数据库驱动时候报如下错误: java.lang.ClassCastException: $Proxy0 cannot be cast to java.sql.Connec</div> </li> <li><a href="/article/1182.htm" title="java泛型" target="_blank">java泛型</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java%E6%B3%9B%E5%9E%8B/1.htm">java泛型</a> <div>泛型 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,任意化的缺点就是要实行强制转换,这种强制转换可能会带来不安全的隐患   泛型的特点:消除强制转换 确保类型安全 向后兼容   简单泛型的定义:      泛型:就是在类中将其模糊化,在创建对象的时候再具体定义 class fan</div> </li> <li><a href="/article/1309.htm" title="javascript闭包[两个小测试例子]" target="_blank">javascript闭包[两个小测试例子]</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>一.程序一 <script> var name = "The Window"; var Object_a = {   name : "My Object",   getNameFunc : function(){ var that = this;     return function(){     </div> </li> <li><a href="/article/1436.htm" title="探索JUnit4扩展:假设机制(Assumption)" target="_blank">探索JUnit4扩展:假设机制(Assumption)</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Assumption/1.htm">Assumption</a><a class="tag" taget="_blank" href="/search/JUnit/1.htm">JUnit</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a> <div>一.假设机制(Assumption)概述        理想情况下,写测试用例的开发人员可以明确的知道所有导致他们所写的测试用例不通过的地方,但是有的时候,这些导致测试用例不通过的地方并不是很容易的被发现,可能隐藏得很深,从而导致开发人员在写测试用例时很难预测到这些因素,而且往往这些因素并不是开发人员当初设计测试用例时真正目的,</div> </li> <li><a href="/article/1563.htm" title="【Gson四】范型POJO的反序列化" target="_blank">【Gson四】范型POJO的反序列化</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/POJO/1.htm">POJO</a> <div>在下面这个例子中,POJO(Data类)是一个范型类,在Tests中,指定范型类为PieceData,POJO初始化完成后,通过 String str = new Gson().toJson(data); 得到范型化的POJO序列化得到的JSON串,然后将这个JSON串反序列化为POJO   import com.google.gson.Gson; import java.</div> </li> <li><a href="/article/1690.htm" title="【Spark八十五】Spark Streaming分析结果落地到MySQL" target="_blank">【Spark八十五】Spark Streaming分析结果落地到MySQL</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/Stream/1.htm">Stream</a> <div>几点总结: 1. DStream.foreachRDD是一个Output Operation,类似于RDD的action,会触发Job的提交。DStream.foreachRDD是数据落地很常用的方法 2. 获取MySQL Connection的操作应该放在foreachRDD的参数(是一个RDD[T]=>Unit的函数类型),这样,当foreachRDD方法在每个Worker上执行时,</div> </li> <li><a href="/article/1817.htm" title="NGINX + LUA实现复杂的控制" target="_blank">NGINX + LUA实现复杂的控制</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/nginx+lua/1.htm">nginx lua</a> <div>安装lua_nginx_module 模块 lua_nginx_module 可以一步步的安装,也可以直接用淘宝的OpenResty Centos和debian的安装就简单了。。 这里说下freebsd的安装: fetch http://www.lua.org/ftp/lua-5.1.4.tar.gz tar zxvf lua-5.1.4.tar.gz cd lua-5.1.4 ma</div> </li> <li><a href="/article/1944.htm" title="java-递归判断数组是否升序" target="_blank">java-递归判断数组是否升序</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> public class IsAccendListRecursive { /*递归判断数组是否升序 * if a Integer array is ascending,return true * use recursion */ public static void main(String[] args){ IsAccendListRecursiv</div> </li> <li><a href="/article/2071.htm" title="Netty源码学习-DefaultChannelPipeline2" target="_blank">Netty源码学习-DefaultChannelPipeline2</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/netty/1.htm">netty</a> <div>Netty3的API http://docs.jboss.org/netty/3.2/api/org/jboss/netty/channel/ChannelPipeline.html 里面提到ChannelPipeline的一个“pitfall”: 如果ChannelPipeline只有一个handler(假设为handlerA)且希望用另一handler(假设为handlerB) 来</div> </li> <li><a href="/article/2198.htm" title="Java工具之JPS" target="_blank">Java工具之JPS</a> <span class="text-muted">chinrui</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>JPS使用     熟悉Linux的朋友们都知道,Linux下有一个常用的命令叫做ps(Process Status),是用来查看Linux环境下进程信息的。同样的,在Java Virtual Machine里面也提供了类似的工具供广大Java开发人员使用,它就是jps(Java Process Status),它可以用来</div> </li> <li><a href="/article/2325.htm" title="window.print分页打印" target="_blank">window.print分页打印</a> <span class="text-muted">ctrain</span> <a class="tag" taget="_blank" href="/search/window/1.htm">window</a> <div> function init() { var tt = document.getElementById("tt"); var childNodes = tt.childNodes[0].childNodes; var level = 0; for (var i = 0; i < childNodes.length; i++) { </div> </li> <li><a href="/article/2452.htm" title="安装hadoop时 执行jps命令Error occurred during initialization of VM" target="_blank">安装hadoop时 执行jps命令Error occurred during initialization of VM</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/jps/1.htm">jps</a> <div>在安装hadoop时,执行JPS出现下面错误   [slave16]root@192.168.11.10:/tmp/hsperfdata_hdfs# jps Error occurred during initialization of VM java.lang.Error: Properties init: Could not determine current working</div> </li> <li><a href="/article/2579.htm" title="PHP开发大型项目的一点经验" target="_blank">PHP开发大型项目的一点经验</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E9%87%8D%E6%9E%84/1.htm">重构</a> <div>一、变量 最好是把所有的变量存储在一个数组中,这样在程序的开发中可以带来很多的方便,特别是当程序很大的时候。变量的命名就当适合自己的习惯,不管是用拼音还是英语,至少应当有一定的意义,以便适合记忆。变量的命名尽量规范化,不要与PHP中的关键字相冲突。 二、函数 PHP自带了很多函数,这给我们程序的编写带来了很多的方便。当然,在大型程序中我们往往自己要定义许多个函数,几十</div> </li> <li><a href="/article/2706.htm" title="android笔记之--向网络发送GET/POST请求参数" target="_blank">android笔记之--向网络发送GET/POST请求参数</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>使用GET方法发送请求 private static boolean sendGETRequest (String path, Map<String, String> params) throws Exception{ //发送地http://192.168.100.91:8080/videoServi</div> </li> <li><a href="/article/2833.htm" title="linux复习笔记 之bash shell (3) 通配符" target="_blank">linux复习笔记 之bash shell (3) 通配符</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/linux+%E9%80%9A%E9%85%8D%E7%AC%A6/1.htm">linux 通配符</a><a class="tag" taget="_blank" href="/search/linux%E9%80%9A%E9%85%8D%E7%AC%A6/1.htm">linux通配符</a> <div>转载请出自出处: http://eksliang.iteye.com/blog/2104387 在bash的操作环境中有一个非常有用的功能,那就是通配符。 下面列出一些常用的通配符,如下表所示 符号 意义 * 万用字符,代表0个到无穷个任意字符 ? 万用字符,代表一定有一个任意字符 [] 代表一定有一个在中括号内的字符。例如:[abcd]代表一定有一个字符,可能是a、b、c</div> </li> <li><a href="/article/2960.htm" title="Android关于短信加密" target="_blank">Android关于短信加密</a> <span class="text-muted">gqdy365</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>关于Android短信加密功能,我初步了解的如下(只在Android应用层试验):     1、因为Android有短信收发接口,可以调用接口完成短信收发;         发送过程:APP(基于短信应用修改)接受用户输入号码、内容——>APP对短信内容加密——>调用短信发送方法Sm</div> </li> <li><a href="/article/3087.htm" title="asp.net在网站根目录下创建文件夹" target="_blank">asp.net在网站根目录下创建文件夹</a> <span class="text-muted">hvt</span> <a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/hovertree/1.htm">hovertree</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/Web+Forms/1.htm">Web Forms</a> <div>假设要在asp.net网站的根目录下建立文件夹hovertree,C#代码如下: string m_keleyiFolderName = Server.MapPath("/hovertree"); if (Directory.Exists(m_keleyiFolderName)) { //文件夹已经存在 return; } else { try { D</div> </li> <li><a href="/article/3214.htm" title="一个合格的程序员应该读过哪些书" target="_blank">一个合格的程序员应该读过哪些书</a> <span class="text-muted">justjavac</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E4%B9%A6%E7%B1%8D/1.htm">书籍</a> <div>编者按:2008年8月4日,StackOverflow 网友 Bert F 发帖提问:哪本最具影响力的书,是每个程序员都应该读的? “如果能时光倒流,回到过去,作为一个开发人员,你可以告诉自己在职业生涯初期应该读一本, 你会选择哪本书呢?我希望这个书单列表内容丰富,可以涵盖很多东西。” 很多程序员响应,他们在推荐时也写下自己的评语。 以前就有国内网友介绍这个程序员书单,不过都是推荐数</div> </li> <li><a href="/article/3341.htm" title="单实例实践" target="_blank">单实例实践</a> <span class="text-muted">跑龙套_az</span> <a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B/1.htm">单例</a> <div>   1、内部类 public class Singleton { private static class SingletonHolder { public static Singleton singleton = new Singleton(); } public Singleton getRes</div> </li> <li><a href="/article/3468.htm" title="PO VO BEAN 理解" target="_blank">PO VO BEAN 理解</a> <span class="text-muted">q137681467</span> <a class="tag" taget="_blank" href="/search/VO/1.htm">VO</a><a class="tag" taget="_blank" href="/search/DTO/1.htm">DTO</a><a class="tag" taget="_blank" href="/search/po/1.htm">po</a> <div>PO:      全称是 persistant object持久对象 最形象的理解就是一个PO就是数据库中的一条记录。 好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。     BO:     全称是 business object:业务对象 主要作用是把业务逻辑封装为一个对象。这个对</div> </li> <li><a href="/article/3595.htm" title="战胜惰性,暗自努力" target="_blank">战胜惰性,暗自努力</a> <span class="text-muted">金笛子</span> <a class="tag" taget="_blank" href="/search/%E5%8A%AA%E5%8A%9B/1.htm">努力</a> <div>偶然看到一句很贴近生活的话:“别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得吊儿郎当,和你一样会抱怨,而只有你自己相信这些都是真的,最后也只有你一人继续不思进取。”很多句子总在不经意中就会戳中一部分人的软肋,我想我们每个人的周围总是有那么些表现得“吊儿郎当”的存在,是否你就真的相信他们如此不思进取,而开始放松了对自己的要求随波逐流呢? 我有个朋友是搞技术的,平时嘻嘻哈哈,以</div> </li> <li><a href="/article/3722.htm" title="NDK/JNI二维数组多维数组传递" target="_blank">NDK/JNI二维数组多维数组传递</a> <span class="text-muted">wenzongliang</span> <a class="tag" taget="_blank" href="/search/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">二维数组</a><a class="tag" taget="_blank" href="/search/jni/1.htm">jni</a><a class="tag" taget="_blank" href="/search/NDK/1.htm">NDK</a> <div>多维数组和对象数组一样处理,例如二维数组里的每个元素还是一个数组 用jArray表示,直到数组变为一维的,且里面元素为基本类型,去获得一维数组指针。给大家提供个例子。已经测试通过。 Java_cn_wzl_FiveChessView_checkWin( JNIEnv* env,jobject thiz,jobjectArray qizidata) { jint i,j; int s</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>