爬蟲

上網(wǎng)原理

上網(wǎng)原理.png

1涧团、爬蟲概念

爬蟲是什麼只磷?

蜘蛛,蛆泌绣,代碼中钮追,就是寫了一段代碼,代碼的功能從互聯(lián)網(wǎng)中提取數(shù)據(jù)

互聯(lián)網(wǎng):

節(jié)點(diǎn)就是url(統(tǒng)一資源定位符)阿迈,有很多a鏈接組成

互聯(lián)網(wǎng)爬蟲:

寫代碼畏陕,模擬瀏覽器訪問url,并且從里面提取指定的內(nèi)容

都有哪些語言可以實(shí)現(xiàn)爬蟲仿滔?

1.php惠毁。號(hào)稱世界上最優(yōu)美的語言,php天生對(duì)多進(jìn)程多線程支持的不好
2.java崎页。是python最主要的競(jìng)爭(zhēng)對(duì)手鞠绰,也說它不好,java語言比較臃腫飒焦,重構(gòu)起來難度太大
3.c蜈膨,c++。也能夠?qū)崿F(xiàn)牺荠,不是最好的選擇翁巍,只能說是能力的體現(xiàn)
4.python,號(hào)稱世界上最美麗的語言休雌,代碼簡(jiǎn)潔灶壶,學(xué)習(xí)成本低,支持的模塊多杈曲,scrapy爬蟲框架

通用爬蟲

百度驰凛、360胸懈、搜狗、谷歌恰响、必應(yīng)等趣钱,搜索引擎

(1)從互聯(lián)網(wǎng)上抓取所有的數(shù)據(jù)
(2)對(duì)數(shù)據(jù)進(jìn)行處理
(3)對(duì)用戶提供檢索服務(wù)
百度如何爬取新的內(nèi)容?
(1)主動(dòng)的將域名提交給百度
(2)在其他網(wǎng)站中設(shè)置友情鏈接
(3)自己會(huì)和dns服務(wù)商進(jìn)行合作

robots協(xié)議:

就是一個(gè)君子協(xié)議胚宦,淘寶就不允許百度抓取

這個(gè)協(xié)議就是一個(gè)文件首有,要放到網(wǎng)站的根目錄

咱寫的爬蟲程序,你就不用遵從了

排名:

(1)根據(jù)一個(gè)值排名枢劝,pagerank绞灼,(seo)

(2)競(jìng)價(jià)排名库北,為浙西事件

缺點(diǎn):

(1)抓取的很多數(shù)據(jù)都是沒用的

(2)不能根據(jù)需求進(jìn)行爬取


聚焦爬蟲

根據(jù)自己的需求印蓖,提取指定的數(shù)據(jù)
我們學(xué)習(xí)的就是聚焦爬蟲

  • 如何實(shí)現(xiàn)抓取指定的數(shù)據(jù):
    (1)每一個(gè)網(wǎng)頁都有自己的唯一的url
    (2)網(wǎng)頁都是由html組成的
    (3)網(wǎng)頁的傳輸使用的都是http、https協(xié)議

  • 爬蟲的思路:

(1)要爬取的網(wǎng)頁的url
(2)寫代碼模擬瀏覽器發(fā)送http請(qǐng)求
(3)解析網(wǎng)頁內(nèi)容曹仗,字符串處理被冒,根據(jù)規(guī)則提取數(shù)據(jù)

開發(fā)環(huán)境

windows军掂、linux都可以

python 3.x 64位
編輯工具:pycharm sublime
整體內(nèi)容介紹:
(1)模擬瀏覽器發(fā)送請(qǐng)求
urllib.request urllib.parse requests
(2)解析內(nèi)容
正則表達(dá)式、bs4昨悼、xpath蝗锥、jsonpath
(3)動(dòng)態(tài)html
selenium+phantomjs
(4)scrapy框架的學(xué)習(xí)
(5)scrapy-redis的組件
(6)涉及到的爬蟲-反爬蟲-反反爬蟲的內(nèi)容

User-Agent、代理率触、驗(yàn)證碼终议、動(dòng)態(tài)數(shù)據(jù)
最終:理論上,只要瀏覽器能夠訪問的數(shù)據(jù)葱蝗,你的程序就能訪問
模擬登錄

2穴张、http協(xié)議

上網(wǎng)原理:看圖形

http和https的區(qū)別:

2悼凑、http是超文本傳輸協(xié)議偿枕,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協(xié)議户辫。

3渐夸、http和https使用的是完全不同的連接方式,用的端口也不一樣渔欢,前者是80墓塌,后者是443。

4、http的連接很簡(jiǎn)單桃纯,是無狀態(tài)的酷誓;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸披坏、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議态坦,比http協(xié)議安全。

http協(xié)議 https://www.cnblogs.com/10158wsj/p/6762848.html

一個(gè)完整的url

    http://www.baidu.com:80/index.html?username=goudan&password=123456&lala=xixi#dudu

協(xié)議 域名 端口號(hào) 請(qǐng)求的資源 get參數(shù) 錨點(diǎn)
錨點(diǎn):可以實(shí)現(xiàn)同一個(gè)頁面的跳轉(zhuǎn)

請(qǐng)求:
請(qǐng)求行棒拂、請(qǐng)求頭伞梯、空行
常見請(qǐng)求頭

accept:瀏覽器通過這個(gè)頭告訴服務(wù)器,它所支持的數(shù)據(jù)類型

Accept-Charset: 瀏覽器通過這個(gè)頭告訴服務(wù)器帚屉,它支持哪種字符集

Accept-Encoding:瀏覽器通過這個(gè)頭告訴服務(wù)器谜诫,支持的壓縮格式(重要)

Accept-Language:瀏覽器通過這個(gè)頭告訴服務(wù)器,它的語言環(huán)境

Host:瀏覽器通過這個(gè)頭告訴服務(wù)器攻旦,想訪問哪臺(tái)主機(jī)

If-Modified-Since: 瀏覽器通過這個(gè)頭告訴服務(wù)器喻旷,緩存數(shù)據(jù)的時(shí)間

Referer:瀏覽器通過這個(gè)頭告訴服務(wù)器,客戶機(jī)是哪個(gè)頁面來的 防盜鏈(重要)

Connection:瀏覽器通過這個(gè)頭告訴服務(wù)器牢屋,請(qǐng)求完后是斷開鏈接還是何持鏈接

User-Agent:客戶端的類型

cookie:和身份有關(guān)的

響應(yīng):狀態(tài)行且预、響應(yīng)頭、實(shí)體內(nèi)容

常見響應(yīng)頭
Location: 服務(wù)器通過這個(gè)頭烙无,來告訴瀏覽器跳到哪里
  
Server:服務(wù)器通過這個(gè)頭锋谐,告訴瀏覽器服務(wù)器的型號(hào)
  
Content-Encoding:服務(wù)器通過這個(gè)頭,告訴瀏覽器截酷,數(shù)據(jù)的壓縮格式
  
Content-Length: 服務(wù)器通過這個(gè)頭涮拗,告訴瀏覽器回送數(shù)據(jù)的長(zhǎng)度
  
Content-Language: 服務(wù)器通過這個(gè)頭,告訴瀏覽器語言環(huán)境
  
Content-Type:服務(wù)器通過這個(gè)頭迂苛,告訴瀏覽器回送數(shù)據(jù)的類型
  
Refresh:服務(wù)器通過這個(gè)頭三热,告訴瀏覽器定時(shí)刷新
  
Content-Disposition: 服務(wù)器通過這個(gè)頭,告訴瀏覽器以下載方式打數(shù)據(jù)
  
Transfer-Encoding:服務(wù)器通過這個(gè)頭三幻,告訴瀏覽器數(shù)據(jù)是以分塊方式回送的
  
**Expires: -1 **控制瀏覽器不要緩存
  Cache-Control: no-cache
  Pragma: no-cache

3康铭、抓包工具

sublime安裝和使用

  • (1)安裝插件管理器,packagecontrol
  • (2)安裝插件
    按:ctrl + shift + p
    輸入pci赌髓,點(diǎn)擊installpackage即可
    搜索想要安裝的插件从藤,敲enter即可安裝
  • (3)卸載插件
    按:ctrl + shift + p
    輸入remove,選中remove package即可

抓包:

谷歌瀏覽器自帶抓包工具
network锁蠕,點(diǎn)擊看詳情
response.headers 響應(yīng)頭部
request.headers 請(qǐng)求頭
query_string 請(qǐng)求字符串夷野,get參數(shù)
formadata 請(qǐng)求參數(shù),post參數(shù)
response:響應(yīng)內(nèi)容
fiddler軟件
專業(yè)的抓包軟件

配置:

4悯搔、urllib庫

是干什么的?是python用來模擬http發(fā)送請(qǐng)求的舌仍,是python自帶的一個(gè)模塊
python2.x :urllib妒貌,urllib2
python3.x :urllib
urllib.request : 發(fā)送請(qǐng)求通危、獲取響應(yīng)
urlopen(url=xxx, data=xxx) : 發(fā)送get,直接將參數(shù)拼接到url的后面灌曙,發(fā)送post菊碟,就需要data參數(shù)了
response對(duì)象:

read() :

讀取的為二進(jìn)制數(shù)據(jù)
字符串類型《====》二進(jìn)制類型

encode() :

字符串格式轉(zhuǎn)化為二進(jìn)制格式,不寫代表utf8在刺,寫gbk就代表gbk

decode() :

二進(jìn)制轉(zhuǎn)為字符串逆害,不寫就是utf8,寫gbk就是gbk

readlines() :

讀取為列表格式蚣驼,按行讀取

getcode() :

獲取狀態(tài)碼

geturl() :

獲取請(qǐng)求的url

getheaders() :

返回響應(yīng)頭部魄幕,列表里面有元組

urlretrieve() :

發(fā)送請(qǐng)求,并且將響應(yīng)信息直接寫入到文件中

urllib.parse :

用來處理數(shù)據(jù)

quote() :

對(duì)url里面的非法字符進(jìn)行編碼颖杏,字母纯陨、數(shù)字、下劃線留储、&翼抠、://

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=78000241_9_hao_pg&wd=%E5%B8%85%E5%93%A5&oq=%25E5%25A7%259A%25E5%25B9%25BF%25E9%2591%25AB&rsv_pq=e7c2fda20000674b&rsv_t=9e64HlBZF4gMz%2Bxagmv2AtmJhzUYbJULwJToXPa78kQ%2BBslZuQB%2BshDyF%2BWpOTya0wv%2BZEwsI98&rqlang=cn&rsv_enter=1&inputT=44615&rsv_sug3=45&rsv_sug1=33&rsv_sug7=101&bs=%E5%A7%9A%E5%B9%BF%E9%91%AB

unquote() :

url解碼

urlencode() :

傳遞一個(gè)字典,將字典轉(zhuǎn)化為

query_stirng ,

并且里面的非法字符得到編碼

5欲鹏、構(gòu)建請(qǐng)求對(duì)象

User-Agent : 客戶端瀏覽器類型

定制請(qǐng)求頭部机久,將自己偽裝成pc瀏覽器

headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT                   6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
            }

    # 構(gòu)建請(qǐng)求對(duì)象
request = urllib.request.Request(url=url, headers=headers)




fiddler使用文檔

1、配置

2赔嚎、使用

左邊:所有的請(qǐng)求

<> : 返回的是html文檔
圖片標(biāo)記:代表是圖片
{json} : 返回json格式
{css} : css文件
js: js文件

右邊:查看某個(gè)請(qǐng)求的詳細(xì)信息

inspectors

右上:這個(gè)請(qǐng)求所有的請(qǐng)求信息

raw:請(qǐng)求的原始信息
webforms:請(qǐng)求所帶參數(shù)膘盖,
query_string代表get參數(shù),formdata代
表post參數(shù)

右下:所有的響應(yīng)信息

raw:查看詳細(xì)的響應(yīng)信息
json:如果返回的是json數(shù)據(jù)尤误,在這里
查看

清除所有請(qǐng)求

removeall 清除所有請(qǐng)求
file==》capture 關(guān)閉或者啟動(dòng)抓包

快捷鍵:

select html : 所有的html請(qǐng)求
select js : 所有的js請(qǐng)求
?baidu : 選中所有帶有baidu的請(qǐng)求
cls : 清除所有的請(qǐng)求

地址編碼

import urllib.parse
# url = 'http://www.baidu.com/index.html?name=狗蛋'
# str1 = urllib.parse.quote(url)
url = 'http://www.baidu.com/index.html?'
data = {
    'username':'狗蛋',
    'pwd':'jsjsjs',
    'height':'175',


}

string1 = urllib.parse.urlencode(data)
print(string1)
url+=string1
print(url)



圖片保存


#
import urllib.request
url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531147620161&di=cc9bfc90e915669e609905a13b01affd&imgtype=0&src=http%3A%2F%2Fnres.ingdan.com%2Fuploads%2F20151210%2F1449737241395228.jpg'
response = urllib.request.urlopen(url)
urllib.request.urlretrieve(url,'tu.jpg')

網(wǎng)頁文件down


import urllib.request
url = 'http://www.sougou.com/'
response = urllib.request.urlopen(url)
with open('sougouq.html','w',encoding='utf-8') as fp:
    fp.write(response.read().decode())
print(response.getcode())



post請(qǐng)求

#百度翻譯初級(jí)入門
import urllib.request
import urllib.parse

post_url = 'http://fanyi.baidu.com/v2transapi'

#data
# word = input('請(qǐng)輸入')
word = 'river'
formdata = {
    'from': 'en',
    'to':'zh',
    'query': word,
    'transtype': 'realtime',
    'simple_means_flag': '3',
    'sign': '555962.825483',
    'token': '8d393681119b809e14f9636ea55337c5',
}

formdata = urllib.parse.urlencode(formdata).encode('utf8')

headers = {
    'Accept': '*/*',

'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Content-Length': '123',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'BAIDUID=9AB6C0FBB652B8E5C0EB2116B4794D8A:FG=1; BIDUPSID=9AB6C0FBB652B8E5C0EB2116B4794D8A; PSTM=1519631202; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=DJsdjlXaDlrZm5TUjdkY0NjSU05SWdaM2dxYlh4dFpwcXlQWnJtVFFSa2JKUnBiQUFBQUFBJCQAAAAAAAAAAAEAAAC8V7VPdGltZbXEcml2ZXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuY8lobmPJaW; H_PS_PSSID=26522_1458_21108_18560_22073; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; PSINO=2; locale=zh; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1531202878,1531203779,1531203784; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1531203784',
'Host': 'fanyi.baidu.com',
'Origin': 'http://fanyi.baidu.com',
'Referer': 'http://fanyi.baidu.com/?aldtype=16047',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
#構(gòu)建請(qǐng)求對(duì)象

# request = urllib.request.Request(url=post_url,headers=headers)
# #獲取相應(yīng)
# resposne = urllib.request.urlopen(request,data=formdata)
# print(resposne.read().decode('utf8'))
request = urllib.request.Request(url=post_url,headers=headers)
response = urllib.request.urlopen(request,data=formdata)
print(response.read().decode('utf8'))

get請(qǐng)求

import urllib.request
import urllib.parse

url = 'https://www.baidu.com/s?'

# word = input('請(qǐng)輸入')
word = '煙臺(tái)'
data = {
    'ie':'utf8',
    'wd':word
}
quit_string = urllib.parse.urlencode(data)
url+=quit_string


headers = {
     'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36'

}

request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
with open( '{}.html'.format(word),'w',encoding='utf-8') as fp:
    fp.write(response.read().decode('utf8'))

ajax get請(qǐng)求

# ajax-get

import urllib.request
import urllib.parse

url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'


print('每頁顯示二十條數(shù)據(jù)')
# page = input('請(qǐng)輸入你要幾頁的數(shù)據(jù)')
page = 4
start = (page-1)*20
limit = 20

data = {
    'start':start,
    'limit':limit,

}


qury_string = urllib.parse.urlencode(data)
url +=qury_string

headers = {
     'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36'

}

request = urllib.request.Request(url = url,headers=headers)

response = urllib.request.urlopen(request)
print(response.read().decode('utf8'))


ajax post 請(qǐng)求

# ajax-post
# kfc
import urllib.request
import urllib.parse
post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'


data = {
   'cname':'北京',
   'pageIndex':'1',
   'pid':'',
   'pageSize':'10',
       
}


data = urllib.parse.urlencode(data).encode('utf8')

headers = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36'

}
request = urllib.request.Request(url=post_url,headers=headers)

resposne = urllib.request.urlopen(request,data=data)
print(resposne.read().decode('utf8'))


爬蟲2

1模擬各種請(qǐng)求方式

get請(qǐng)求

import urllib.request
import urllib.parse

url = 'https://www.baidu.com/s?'
word = input('請(qǐng)輸入要查詢的內(nèi)容:')
# get參數(shù)寫到這里
data = {
    'ie': 'utf8',
    'wd': word,
}

# 拼接url
query_string = urllib.parse.urlencode(data)

url += query_string

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

# 構(gòu)建請(qǐng)求對(duì)象
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)

filename = word + '.html'
# 寫入到文件中
with open(filename, 'wb') as fp:
    fp.write(response.read())

# 插件侠畔,sublime-repl


post請(qǐng)求

  • 百度翻譯 XMLHttpRequest
import urllib.request
import urllib.parse

post_url = 'http://fanyi.baidu.com/sug'
# word = input('請(qǐng)輸入要查詢的英文單詞:')
word = 'baby'
# post攜帶的參數(shù)
data = {
    'kw': word
}
# 對(duì)post參數(shù)進(jìn)行處理
data = urllib.parse.urlencode(data).encode('utf8')

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
# 構(gòu)建請(qǐng)求對(duì)象
request = urllib.request.Request(url=post_url, headers=headers)
# 發(fā)送請(qǐng)求
response = urllib.request.urlopen(request, data=data)

print(response.read().decode('utf8'))

進(jìn)階

import urllib.request
import urllib.parse

post_url = 'http://fanyi.baidu.com/v2transapi'

# post參數(shù)
formdata = {
    'from': 'en',
    'to': 'zh',
    'query': 'baby',
    'transtype': 'realtime',
    'simple_means_flag': '3',
    'sign': '814534.560887',
    'token': '921cc5d0819e0f1b4212c7fdc3b23866',
}

# 處理表單數(shù)據(jù)
formdata = urllib.parse.urlencode(formdata).encode('utf8')

headers = {
    'Accept': '*/*',
    # 'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    # 'Content-Length': '121',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Cookie': 'BAIDUID=59CCBF5477FDC81799054A3DA85BEF88:FG=1; BIDUPSID=59CCBF5477FDC81799054A3DA85BEF88; PSTM=1529815427; pgv_pvi=2975680512; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; locale=zh; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; H_PS_PSSID=1436_26432_21094_20929; PSINO=2; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1531189205,1531202737; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1531202737',
    'Host': 'fanyi.baidu.com',
    'Origin': 'http://fanyi.baidu.com',
    'Referer': 'http://fanyi.baidu.com/?aldtype=16047',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
}

# 構(gòu)建請(qǐng)求對(duì)象,發(fā)送請(qǐng)求
request = urllib.request.Request(url=post_url, headers=headers)

# 發(fā)送請(qǐng)求
response = urllib.request.urlopen(request, data=formdata)

print(response.read().decode('utf-8'))



ajax-get請(qǐng)求

import urllib.request
import urllib.parse

url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'

print('每頁顯示20條數(shù)據(jù)')
# page = input('請(qǐng)輸入要第幾頁數(shù)據(jù):')
page = 3

# 根據(jù)page就可以計(jì)算出來start和limit的值
start = (page-1) * 20
limit = 20

# 寫get參數(shù)
data = {
    'start': start,
    'limit': limit,
}

# 將字典轉(zhuǎn)化為query_string格式
query_string = urllib.parse.urlencode(data)

# 拼接url
url += query_string

# print(url)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)

print(response.read().decode('utf8'))

ajax-post請(qǐng)求

  • 肯德基店鋪位置
import urllib.request
import urllib.parse

post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
    'cname': '石河子',
    'pid': '',
    'pageIndex': '1',
    'pageSize': '10',
}
# 處理data數(shù)據(jù)
data = urllib.parse.urlencode(data).encode('utf8')
# 
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=post_url, headers=headers)

response = urllib.request.urlopen(request, data=data)

print(response.read().decode())

2损晤、復(fù)雜get

百度貼吧
  • https://tieba.baidu.com/f?kw=%E6%9D%8E%E6%AF%85&ie=utf-8&pn=0
    第一頁 pn=0
    第二頁 pn=50
    第三頁 pn=100
    第n頁 pn=(n-1)*50
    輸入吧名软棺,輸入要爬取的起始頁碼,輸入要爬取的結(jié)束頁碼
    在當(dāng)前創(chuàng)建一個(gè)文件夾尤勋,文件夾名字就是吧名喘落,在吧名文件夾里面,有好多文件最冰,就每一頁的內(nèi)容瘦棋,第1頁.html 第2頁.html xxxx
import urllib.request
import urllib.parse
import os
import time


def handle_request(url, baname, page):
   pn = (page-1) * 50
   # 拼接url
   data = {
       'ie': 'utf8',
       'kw': baname,
       'pn': pn,
   }
   query_string = urllib.parse.urlencode(data)
   url += query_string
   # print(url)
   headers = {
       'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
   }
   request = urllib.request.Request(url=url, headers=headers)

   return request

# 根據(jù)請(qǐng)求對(duì)象,下載指定的響應(yīng)內(nèi)容到本地
def download(request, baname, page):
   # 根據(jù)吧名暖哨,創(chuàng)建文件夾的過程
   # 判斷文件夾是否存在赌朋,不存在才創(chuàng)建
   if not os.path.exists(baname):
       os.mkdir(baname)
   # 文件的名字
   filename = '第%s頁.html' % page
   print('正在下載%s......' % filename)
   # 拼接文件的全路徑
   filepath = os.path.join(baname, filename)

   response = urllib.request.urlopen(request)
   # 將內(nèi)容都進(jìn)來
   content = response.read()
   # 將內(nèi)容寫入到文件中
   with open(filepath, 'wb') as fp:
       fp.write(content)

   print('結(jié)束下載%s' % filename)


def main():
   url = 'https://tieba.baidu.com/f?'
   # 要爬取的貼吧的名字
   baname = input('請(qǐng)輸入要爬取的吧名:')
   # 起始頁碼、結(jié)束頁碼
   start_page = int(input('請(qǐng)輸入起始頁碼:'))
   end_page = int(input('請(qǐng)輸入結(jié)束頁碼:'))
   # 搞個(gè)循環(huán)
   for page in range(start_page, end_page + 1):
       # 根據(jù)不同的page生成不同哦url,然后生成不同的請(qǐng)求
       request = handle_request(url, baname, page)
       # 發(fā)送請(qǐng)求沛慢,獲取響應(yīng)
       download(request, baname, page)
       # 停頓一下
       time.sleep(2)


if __name__ == '__main__':
   main()


3赡若、URLError\HTTPError

  • 異常處理,NameError, 這兩個(gè)異常在urllib.error里面

  • URLError:不存在的域名团甲,電腦沒有聯(lián)網(wǎng)
    www.goudan.com

  • HTTPError: 404找不到頁面

  • HTTPError是URLError的子類,如果多個(gè)except在進(jìn)行捕獲逾冬,HTTPError要寫到前面

import urllib.request
import urllib.error

'''
url = 'http://www.maodan.com/'

try:
    response = urllib.request.urlopen(url)
except Exception as e:
    print(e)
'''

url = 'https://blog.csdn.net/hudeyu777/article/details/76021574'
try:
    response = urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
    print(e)
except urllib.error.URLError as e:
    print(e)


4、Handler處理器伐庭、自定義Opener

是什麼意思呢粉渠?
++++引入請(qǐng)求對(duì)象為了定制頭部

更高級(jí)的功能就要使用handler和opener分冈,步驟都是首先創(chuàng)建一個(gè)handler圾另,然后創(chuàng)建一個(gè)opener,然后通過opener的open方法來發(fā)送請(qǐng)求

通過handler和opener實(shí)現(xiàn)最基本的請(qǐng)求

import urllib.request

url = 'http://www.baidu.com/'
# 創(chuàng)建一個(gè)handler
handler = urllib.request.HTTPHandler()
# 根據(jù)handler來創(chuàng)建一個(gè)opener
opener = urllib.request.build_opener(handler)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

request = urllib.request.Request(url=url, headers=headers)
# 再往下發(fā)送請(qǐng)求操作雕沉,都通過opener的open方法集乔,沒有urlopen()這個(gè)方法了
response = opener.open(request)

print(response.read().decode('utf8'))

5、代理

  • 代理:代駕坡椒,代購扰路,代練
    我們的代理
    代理服務(wù)器:
--------------------西祠代理
--------------------快代理
  • 瀏覽器配置代理
    101.236.21.22:8866
程序配置代理
import urllib.request

url = 'http://www.baidu.com/s?ie=UTF-8&wd=ip'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

request = urllib.request.Request(url, headers=headers)

# 101.236.21.22:8866
# 使用代理訪問
handler = urllib.request.ProxyHandler(proxies={'http': '101.236.21.22:8866'})
# 根據(jù)handler創(chuàng)建opener
opener = urllib.request.build_opener(handler)

response = opener.open(request)

with open('daili.html', 'wb') as fp:
    fp.write(response.read())

6、cookie

cookie是什麼倔叼?會(huì)員卡

為什么引入cookie汗唱?http有一個(gè)特點(diǎn),無狀態(tài)

每次的請(qǐng)求和響應(yīng)都是獨(dú)立的丈攒,沒有什么關(guān)系
缺點(diǎn)哩罪?
兩次請(qǐng)求如果有聯(lián)系,服務(wù)端識(shí)別不出來
要想識(shí)別出來巡验,引入了cookie

day03-爬蟲3

1际插、cookie

常用在模擬登錄中

通過代碼如何訪問登錄后的頁面?

http://www.renren.com/960481378/profile

  • (1)偽造cookie显设,進(jìn)行訪問
  • (2)模擬瀏覽器的方式框弛,首先發(fā)送post,先登錄成功捕捂,然后發(fā)送get瑟枫,訪問登錄后的頁面
    ps:fiddler上面,一個(gè)本上面有個(gè)箭頭指攒,這個(gè)就是post請(qǐng)求
import urllib.request
import urllib.parse


# 直接訪問這個(gè)頁面慷妙,肯定是不行的,需要偽造cookie
url = 'http://www.renren.com/960481378/profile'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)

with open('renren.html', 'wb') as fp:
    fp.write(response.read())



# 通過抓包幽七,抓取瀏覽器訪問時(shí)候的cookie景殷,通過代碼模擬發(fā)送即可

url = 'http://www.renren.com/960481378/profile'
headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Cookie': 'anonymid=jjgfrq7uasf0qc; depovince=GW; jebecookies=49de5f46-0b80-490f-9277-f19688fc91a3|||||; _r01_=1; JSESSIONID=abcYl2ngsw4FBhTX16gsw; ick_login=52175eb0-6f30-4f87-b614-91fa81350f73; _de=F872F5698F7602B30ADE65415FC01940; p=42e7d8c2c4c06f39f70b2be38468f15f8; first_login_flag=1; ln_uact=17701256561; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=d34342f75a43ffa1c061400e9126ea118; societyguester=d34342f75a43ffa1c061400e9126ea118; id=960481378; xnsid=79143e47; ver=7.0; loginfrom=null; wp_fold=0; jebe_key=2f649712-9cf8-44a8-8c6a-145cfab423ae%7C86ba94a3b75a9848502e25ac92562959%7C1531272254868%7C1',
    'Host': 'www.renren.com',
    'Referer': 'http://www.renren.com/960481378/profile',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)

with open('renren.html', 'wb') as fp:
    fp.write(response.read())

模擬登陸人人網(wǎng)獲取登陸后的界面
import urllib.request
import urllib.parse
import http.cookiejar

# 高級(jí)請(qǐng)求cookie的代碼實(shí)現(xiàn)
# 這個(gè)ck對(duì)象可以保存cookie
ck = http.cookiejar.CookieJar()
# 根據(jù)ck對(duì)象創(chuàng)建一個(gè)handler
handler = urllib.request.HTTPCookieProcessor(ck)
# 根據(jù)handler創(chuàng)建一個(gè)opener
opener = urllib.request.build_opener(handler)

# 往下所有的請(qǐng)求都使用opener.open()方法進(jìn)行發(fā)送,這樣就會(huì)和瀏覽器的功能一模一樣,就是保存cookie并且自動(dòng)攜帶cookie發(fā)送請(qǐng)求的功能

# 抓包獲取到post_url
post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201863950868'
# 表單數(shù)據(jù)
data = {
    'email': '17701256561',
    'icode': '',
    'origURL': 'http://www.renren.com/home',
    'domain': 'renren.com',
    'key_id': '1',
    'captcha_type': 'web_login',
    'password': '776f67653bd0b50d6159b7b5173b74249b9e0765da701ff559c986054b9871a7',
    'rkey': 'fe41ddb7ec32db83d8bdbcc6945e267a',
    'f': 'http%3A%2F%2Fwww.renren.com%2F960481378%2Fprofile',
}
data = urllib.parse.urlencode(data).encode('utf8')

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

request = urllib.request.Request(url=post_url, headers=headers)

response = opener.open(request, data=data)


print(response.read().decode('utf8'))
# with open('renren.html', 'wb') as fp:
#   fp.write(response.read())


# 訪問登錄后的頁面
url = 'http://www.renren.com/960481378/profile'
headers1 = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers1)

response = opener.open(request)

with open('renren.html', 'wb') as fp:
    fp.write(response.read())

2猿挚、正則表達(dá)式

為什么引入正則表達(dá)式咐旧?

  • 字符串,處理函數(shù)也非常重要绩蜻,比如如果要去一個(gè)文件查找所有的郵箱
    test@163.com
    889910@qq.com

  • 正則表達(dá)式铣墨。可以匹配一類的東西办绝,肯定有好多規(guī)則

  • 世界上最難懂四種東西伊约。女人的心,醫(yī)生的處方孕蝉、道士的符屡律、程序媛的正則

正則表達(dá)式規(guī)則

1.單字符匹配:

. : 除了換行符以外所有的字符

\d : 匹配 0-9 [0-9] [1-5]

\D: 除了\d

\w : 數(shù)字、字母降淮、下劃線 [a-zA-Z0-9_]

\W : 除了\w

\s : 所有的空白字符超埋,tab、空格 佳鳖。霍殴。。

\S : 除了\s

[aeiou] : 匹配中括號(hào)里面任意個(gè)

2.數(shù)量修飾:

{5} : 修飾前面的字符出現(xiàn)5次

{5,8} : 5-8次

a{5,8}

aaaaaaaa 貪婪的

{5,} : 最少是5次

{0,} : 任意多次 *

{1,} : 至少1次 +

{0,1} : 可有可無 ?

python模塊 re

re.match(): >>>> 從頭開始匹配系吩,匹配成功就返回
re.search() >>>> 從任意位置開始匹配来庭,匹配成功返回 只找一個(gè)
返回的是對(duì)象, >>>> obj.group()
re.findall() :>>>>>查找所有符合要求的字符串
返回的是列表穿挨,列表里面都是匹配成功的字符串

3.邊界:

^ : 以xxx開頭

$ : 以xxx結(jié)尾

4.分組:

a(bc){5}

小括號(hào)作用
  • (1)視為一個(gè)整體
  • (2)子模式
貪婪模式:
.*
.+
.*? 取消貪婪
.+? 取消貪婪
模式修正
re.I : 忽略大小寫
re.M : 視為多行模式
re.S : 視為單行模式
import re

# 創(chuàng)建正則對(duì)象

pattern = re.compile(r'\d{3,5}')
string = '我以前總共談過1234567次戀愛,我總共結(jié)婚7654321次'

# ret = pattern.match(string)
# ret = pattern.search(string)
ret = pattern.findall(string)

print(ret)



pattern = re.compile(r'a(bc){3}')
string = '哈哈呵呵abcbcbcbcbc嘻嘻嘿嘿么么'

ret = pattern.search(string)

print(ret.group())



string = '哈哈<div><span>醉臥沙場(chǎng)君莫笑,古來征戰(zhàn)幾人回</span></div>嘻嘻'
pattern = re.compile(r'<(\w+)><(\w+)>.+</\2></\1>')

ret = pattern.search(string)

print(ret.group())



string = '<div>兩岸猿聲啼不住,輕舟已過萬重山</div></div></div>'

pattern = re.compile(r'<div>.*?</div>')

ret = pattern.search(string)

print(ret.group())


"""
string = '''english
love is a forever problem
love is feel
'''

pattern = re.compile(r'^love', re.M)

ret = pattern.search(string)
print(ret.group())
"""

"""
string = '''<div>細(xì)思極恐
你的對(duì)手在看書
你的敵人在磨刀
你的閨蜜在減肥
隔壁老王在練腰
</div>
'''
pattern = re.compile(r'<div>.*</div>', re.S)
ret = pattern.search(string)
print(ret.group())
"""

def fn(ret):
    number = int(ret.group())
    number += 1

    return str(number)

# 正則替換
string = '男人都喜歡19歲的女孩'

pattern = re.compile(r'\d+')

# ret = pattern.sub('40', string)
ret = pattern.sub(fn, string)

print(ret)

糗事百科圖片--實(shí)戰(zhàn)

import urllib.request
import urllib.parse
import re
import os
import time

def handle_request(url, page):
    url += str(page) + '/'
    # print(url)
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    request = urllib.request.Request(url=url, headers=headers)
    return request

def parse_content(request):
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf8')
    with open('lala.html', 'w', encoding='utf8') as fp:
        fp.write(content)
    # 解析內(nèi)容月弛,提取這一頁所有的圖片鏈接
    pattern = re.compile(r'<div class="thumb">.*?<a href=".*?" target="_blank">.*?<img src="(.*?)" alt="(.*?)" />.*?</div>', re.S)

    ret = pattern.findall(content)
    # print(ret)
    # exit()
    # print(len(ret))
    download(ret)

def download(ret):
    for image_info in ret:
        # 取出圖片的鏈接
        image_src = image_info[0]
        # 取出圖片的標(biāo)題
        image_alt = image_info[1]
        # 拼接完整的url
        image_src = 'https:' + image_src
        dirname = 'tupian'
        # 創(chuàng)建文件夾
        if not os.path.exists(dirname):
            os.mkdir(dirname)
        # 得到后綴名
        suffix = image_src.split('.')[-1]
        # 文件名字
        filename = image_alt + '.' + suffix
        filepath = os.path.join(dirname, filename)

        print('正在下載%s......' % filename)
        # 下載圖片
        urllib.request.urlretrieve(image_src, filepath)
        print('結(jié)束下載%s' % filename)
        time.sleep(3)


def main():
    start_page = int(input('請(qǐng)輸入要爬取的起始頁碼:'))
    end_page = int(input('請(qǐng)輸入要爬取的結(jié)束頁碼:'))
    url = 'https://www.qiushibaike.com/pic/page/'
    for page in range(start_page, end_page + 1):
        print('正在下載第%s頁......' % page)
        # 拼接url。構(gòu)建請(qǐng)求對(duì)象
        request = handle_request(url, page)
        # 發(fā)送請(qǐng)求絮蒿,獲取響應(yīng)尊搬,并且解析內(nèi)容
        parse_content(request)
        print('結(jié)束下載第%s頁' % page)
        time.sleep(3)

if __name__ == '__main__':
    main()

勵(lì)志語句--實(shí)戰(zhàn)

import urllib.request
import urllib.parse
import re
import time


def main():
    url = 'http://www.yikexun.cn/lizhi/qianming/list_50_{}.html'
    start_page = int(input('請(qǐng)輸入起始頁碼:'))
    end_page = int(input('請(qǐng)輸入結(jié)束頁碼:'))
    # 在這里打開文件
    fp = open('lizhi.html', 'w', encoding='utf8')
    for page in range(start_page, end_page + 1):
        print('正在爬取第%s頁......' % page)
        # 拼接url,生成請(qǐng)求對(duì)象
        request = handle_request(url, page)
        content = urllib.request.urlopen(request).read().decode('utf8')
        # 解析內(nèi)容函數(shù)
        parse_content(content, fp)
        print('結(jié)束爬取第%s頁' % page)
        time.sleep(2)
    fp.close()

def handle_request(url, page=None):
    if page:
        url = url.format(page)
    # print(url)
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    return urllib.request.Request(url=url, headers=headers)

def parse_content(content, fp):
    # 寫正則表達(dá)式土涝,提取所有的標(biāo)題和鏈接
    pattern = re.compile(r'<h3><a href="(/lizhi/qianming/\d+\.html)">(.*?)</a></h3>')
    ret = pattern.findall(content)

    # print(ret)
    # print(len(ret))
    i = 0
    for href_title in ret:
        # 取出鏈接
         + href_title[0]
        # 取出標(biāo)題
        title = href_title[1]
        print('正在爬取%s......' % title)
        # 因?yàn)橹挥械谝粋€(gè)title兩邊有b標(biāo)簽佛寿,所以這里寫了一個(gè)小小的判斷,只在循環(huán)第一次執(zhí)行
        if i == 0:
            # 將title兩邊的b標(biāo)簽干掉
            title = title.strip('<>b/')
            i += 1
        # print(title)
        # 獲取內(nèi)容的函數(shù)
        text = get_text(href)
        # 將標(biāo)題和內(nèi)容寫入到文件中
        string = '<h1>%s</h1>%s' % (title, text)
        fp.write(string)
        print('結(jié)束爬取%s...' % title)

        time.sleep(2)

def get_text(href):
    # 構(gòu)建請(qǐng)求對(duì)象但壮,發(fā)送請(qǐng)求冀泻,解析響應(yīng),返回解析后的內(nèi)容
    request = handle_request(href)
    content = urllib.request.urlopen(request).read().decode('utf8')
    pattern = re.compile(r'<div class="neirong">(.*?)</div>', re.S)
    ret = pattern.search(content)
    # print(ret.group(1))
    # exit()
    text = ret.group(1)
    # 將圖片鏈接去除掉
    pattern = re.compile(r'<img .*?>')
    text = pattern.sub('', text)
    return text

if __name__ == '__main__':
    main()

day04-爬蟲4

1蜡饵、bs4語法

是什麼弹渔?
BeautifulSoup,就是一個(gè)第三方的庫溯祸,使用之前需要安裝
  • pip install bs4

  • pip進(jìn)行安裝肢专,默認(rèn)是從國外安裝舞肆,所以需要將pip源設(shè)置為國內(nèi)源,國內(nèi)有豆瓣源博杖、阿里源椿胯、網(wǎng)易源等等xxx

配置永久國內(nèi)源:

  • 1.windows配置方式:

(1)打開文件資源管理器
--------在地址欄中輸入 %appdata%
(2)手動(dòng)創(chuàng)建一個(gè)文件夾叫做 pip
(3)在pip的文件夾里面新建一個(gè)文件 pip.ini
(4)文件中寫如下內(nèi)容

[global]
index-url = http://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com
  • linux配置方式:

(1)cd ~
(2)mkdir .pip
(3)vi ~/.pip/pip.conf
(4)編輯內(nèi)容和windows的內(nèi)容一模一樣

pip install bs4 pip install lxml
bs4是什麼?
  • 它的作用是能夠快速方便簡(jiǎn)單的提取網(wǎng)頁中指定的內(nèi)容剃根,給我一個(gè)網(wǎng)頁字符串哩盲,然后使用它的接口將網(wǎng)頁字符串生成一個(gè)對(duì)象,然后通過這個(gè)對(duì)象的方法來提取數(shù)據(jù)
lxml是什麼狈醉?
  • lxml是一個(gè)解析器廉油,也是下面的xpath要用到的庫,bs4將網(wǎng)頁字符串生成對(duì)象的時(shí)候需要用到解析器苗傅,就用lxml抒线,或者使用官方自帶的解析器 html.parser

bs4語法學(xué)習(xí)

  • 通過本地文件進(jìn)行學(xué)習(xí),通過網(wǎng)絡(luò)進(jìn)行寫代碼
    (1)根據(jù)標(biāo)簽名進(jìn)行獲取節(jié)點(diǎn)
    只能找到第一個(gè)符合要求的節(jié)點(diǎn)
    (2)獲取文本內(nèi)容和屬性
  • 屬性

soup.a.attrs 返回一字典金吗,里面是所有屬性和值
soup.a['href'] 獲取href屬性

  • 文本

soup.a.string
soup.a.text
soup.a.get_text()
【注】當(dāng)標(biāo)簽里面還有標(biāo)簽的時(shí)候十兢,string獲取的為None趣竣,其他兩個(gè)獲取純文本內(nèi)容

(3)find方法

soup.find('a')
soup.find('a', class_='xxx')
soup.find('a', title='xxx')
soup.find('a', id='xxx')
soup.find('a', id=re.compile(r'xxx'))
【注】find只能找到符合要求的第一個(gè)標(biāo)簽摇庙,他返回的是一個(gè)對(duì)象

(4)find_all

返回一個(gè)列表,列表里面是所有的符合要求的對(duì)象
soup.find_all('a')
soup.find_all('a', class_='wang')
soup.find_all('a', id=re.compile(r'xxx'))
soup.find_all('a', limit=2) 提取出前兩個(gè)符合要求的a

(5)select

選擇遥缕,選擇器 css中
常用的選擇器
標(biāo)簽選擇器卫袒、id選擇器、類選擇器
層級(jí)選擇器**
div h1 a 后面的是前面的子節(jié)點(diǎn)即可
div > h1 > a 后面的必須是前面的直接子節(jié)點(diǎn)
屬性選擇器
input[name='hehe']
select('選擇器的')
【注】返回的是一個(gè)列表单匣,列表里面都是對(duì)象
【注】find find_all select不僅適用于soup對(duì)象夕凝,還適用于其他的子對(duì)象,如果調(diào)用子對(duì)象的select方法户秤,那么就是從這個(gè)子對(duì)象里面去找符合這個(gè)選擇器的標(biāo)簽

from bs4 import BeautifulSoup

# 生成soup對(duì)象
soup = BeautifulSoup(open('soup.html', encoding='utf8'), 'lxml')
print(type(soup))

print(soup.a.attrs)
print(soup.a.attrs['href'])
print(soup.a['href'])

print(soup.a.string)
print(soup.a.text)
print(soup.a.get_text())

print(soup.div.string)
print(soup.div.text)
print(soup.div.get_text())

ret = soup.find('a')
ret = soup.find('a', title='清明')
ret = soup.find('a', class_='dumu')
print(ret)

import re
ret = soup.find('a', id='xiaoge')
ret = soup.find('a', id=re.compile(r'^x'))
print(ret.string)

ret = soup.find_all('a')
print(ret[1].string)

ret = soup.find_all('a', class_='wang')
print(ret)

ret = soup.find_all('a', id=re.compile(r'^x'))
print(ret)

ret = soup.select('a')
ret = soup.select('#muxiong')
print(ret[0]['title'])

ret = soup.select('.wang')
print(ret)

ret = soup.select('div > a')
print(ret)

ret = soup.select('a[title=東坡肉]')

print(ret)

odiv = soup.select('.tang')[0]

ret = odiv.select('a')

print(ret)

滾滾長(zhǎng)江東逝水码秉,浪花淘盡英雄,是非成敗轉(zhuǎn)頭看鸡号,青山依舊在转砖,幾度夕陽紅
白發(fā)漁樵江渚上,觀看秋月春風(fēng)鲸伴,一壺濁酒喜相逢府蔗,古今多少事,都付笑談中

三國演義--實(shí)戰(zhàn)

import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
import time

# 給我一個(gè)url汞窗,返回一個(gè)請(qǐng)求對(duì)象
def handle_request(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    return urllib.request.Request(url=url, headers=headers)

def parse_first_page(url):
    request = handle_request(url)
    # 發(fā)送請(qǐng)求姓赤,獲取響應(yīng)
    content = urllib.request.urlopen(request).read().decode('utf8')
    time.sleep(2)
    # 使用bs解析內(nèi)容,生成soup對(duì)象
    soup = BeautifulSoup(content, 'lxml')
    # print(soup)
    # 查找所有的章節(jié)鏈接對(duì)象
    a_list = soup.select('.book-mulu > ul > li > a')
    # print(ret)
    # print(len(ret))
    # 打開文件
    fp = open('三國演義.txt', 'w', encoding='utf8')
    # 遍歷所有的a對(duì)象
    for oa in a_list:
        # 取出這個(gè)a的內(nèi)容
        title = oa.string
        # 取出a的href屬性
         + oa['href']

        print('正在下載%s......' % title)
        # 向href發(fā)送請(qǐng)求,直接獲取到解析之后的內(nèi)容
        neirong = get_neirong(href)
        print('結(jié)束下載%s' % title)
        time.sleep(2)
        string = '%s\n%s' % (title, neirong)
        # 將string寫入到文件中
        fp.write(string)

    fp.close()

def get_neirong(href):
    # 向href發(fā)送請(qǐng)求仲吏,獲取響應(yīng)不铆,解析響應(yīng)蝌焚,返回內(nèi)容
    request = handle_request(href)
    content = urllib.request.urlopen(request).read().decode('utf8')
    # 生成soup對(duì)象,提取章節(jié)內(nèi)容
    soup = BeautifulSoup(content, 'lxml')
    # 找包含章節(jié)內(nèi)容的div
    odiv = soup.find('div', class_='chapter_content')
    neirong = odiv.text
    return neirong

def main():
    url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
    # 解析第一個(gè)頁面誓斥,返回所有的章節(jié)列表
    chapter_list = parse_first_page(url)

if __name__ == '__main__':
    main()

智聯(lián)招聘--實(shí)戰(zhàn)

import urllib.request
import urllib.parse
import time
from bs4 import BeautifulSoup

class ZhiLianSpider(object):
    def __init__(self, jl, kw, start_page, end_page):
        # 保存到成員屬性中综看,這樣在其他的方法中就可以直接使用
        self.jl = jl
        self.kw = kw
        self.start_page = start_page
        self.end_page = end_page

        self.items = []

    def handle_request(self, page):
        url = 'https://sou.zhaopin.com/jobs/searchresult.ashx?'
        data = {
            'jl': self.jl,
            'kw': self.kw,
            'p': page,
        }
        query_string = urllib.parse.urlencode(data)
        # 拼接url
        url += query_string
        # print(url)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
        }
        return urllib.request.Request(url=url, headers=headers)

    def parse_content(self, content):
        # 生成soup對(duì)象
        soup = BeautifulSoup(content, 'lxml')
        # 首先找到所有的table
        table_list = soup.find_all('table', class_='newlist')[1:]
        # print(table_list)
        # print(len(table_list))
        # 遍歷所有的table,依次提取每一個(gè)工作的信息
        for table in table_list:
            # 職位名稱
            zwmc = table.select('.zwmc a')[0].text.strip('\xa0')
            # 公司名稱
            gsmc = table.select('.gsmc a')[0].text
            # 職位月薪
            zwyx = table.select('.zwyx')[0].text
            # 工作地點(diǎn)
            gzdd = table.select('.gzdd')[0].text
            # print(gzdd)
            # exit()
            item = {
                '職位名稱': zwmc,
                '公司名稱': gsmc,
                '職位月薪': zwyx,
                '工作地點(diǎn)': gzdd,
            }
            self.items.append(item)

    def run(self):
        # 搞個(gè)循環(huán)
        for page in range(self.start_page, self.end_page + 1):
            print('正在爬取第%s頁......' % page)
            # 拼接url的過程岖食,構(gòu)建請(qǐng)求對(duì)象
            request = self.handle_request(page)
            content = urllib.request.urlopen(request).read().decode('utf8')
            # 給我請(qǐng)求對(duì)象红碑,解析并且提取內(nèi)容
            self.parse_content(content)
            print('結(jié)束爬取第%s頁' % page)
            time.sleep(2)

        # 將所有的工作保存到文件中
        string = str(self.items)
        with open('work.txt', 'w', encoding='utf8') as fp:
            fp.write(string)

def main():
    # 輸入工作地點(diǎn)
    jl = input('請(qǐng)輸入工作地點(diǎn):')
    # 輸入工作關(guān)鍵字
    kw = input('請(qǐng)輸入關(guān)鍵字:')
    # 輸入起始頁碼
    start_page = int(input('請(qǐng)輸入起始頁碼:'))
    # 輸入結(jié)束頁碼
    end_page = int(input('請(qǐng)輸入結(jié)束頁碼:'))
    zhilian = ZhiLianSpider(jl, kw, start_page, end_page)
    zhilian.run()

if __name__ == '__main__':
    main()

2、xpath語法

xml : 和json是一樣的泡垃,用在數(shù)據(jù)交互和傳輸中析珊,但是到現(xiàn)在用的基本上都是json格式
為什么使用json格式?因?yàn)閖s原生支持

xpath : 就是用來解析xml數(shù)據(jù)的
因?yàn)檫@個(gè)xml和html很像蔑穴,所以在python里面有一個(gè)第三方庫 lxml忠寻,提供了一些xpath可以解析html的一些函數(shù),你可以直接使用

pip install lxml

xpath簡(jiǎn)單語法:

/ ----------根節(jié)點(diǎn)開始查找
// --------從任意位置開始查找
. ---------從當(dāng)前節(jié)點(diǎn)開始查找
.. -----從上一級(jí)節(jié)點(diǎn)開始查找
@ -----------選取屬性

bookstore/book :查找bookstore這個(gè)節(jié)點(diǎn)下面所有的book存和,直接子節(jié)點(diǎn)
//book : 在整個(gè)文檔中查找所有的book
bookstore//book :查找bookstore下面所有的book
//@lang :-查找所有擁有l(wèi)ang屬性的節(jié)點(diǎn)
bookstore/book[1] :查找第一個(gè)book奕剃,下標(biāo)從1開始
bookstore/book[last()] :-最后一個(gè)book
bookstore/book[last()-1] : 倒數(shù)第二個(gè)
//title[@lang] :所有的有l(wèi)ang屬性的title
//title[@lang='eng'] :所有的lang屬性的值為eng的title節(jié)點(diǎn)

day05-爬蟲5

1、xpath使用

安裝xpath插件

  • 啟動(dòng)和關(guān)閉插件: ctrl + shift + x

常用的xpath

(1)屬性定位

  • 查找id=kw的input框

//input[@id="kw"]

(2)層級(jí)和索引定位

//div[@id="head"]/div/div[3]/a[2]

(3)模糊匹配

contains
class屬性包含av的所有a
//a[contains(@class,"av")]

內(nèi)容包含產(chǎn)品的所有a
//a[contains(text(),"產(chǎn)品")]

starts_with
starts-with
class以m開頭的所有a
//a[starts-with(@class,"m")]

內(nèi)容以新開頭的所有a
//a[starts-with(text(),"新")]

(4)取文本和屬性

  • 找內(nèi)容以新開頭的所有a標(biāo)簽的文本內(nèi)容

//a[starts-with(text(),"新")]/text()

  • 找內(nèi)容以新開頭的所有a標(biāo)簽的href屬性

//a[starts-with(text(),"新")]/@href

代碼中操作xpath

步驟:給一個(gè)網(wǎng)頁字符串捐腿,會(huì)將網(wǎng)頁字符串生成對(duì)象纵朋,然后根據(jù)對(duì)象的xpath方法去找指定的節(jié)點(diǎn)即可

from lxml import etree

# 將本地的文件生成tree對(duì)象
tree = etree.parse('xpath.html')

# ret = tree.xpath('//li[@id="fei"]')
# ret = tree.xpath('//div[@class="mingju"]/ul/li[2]/a')
# ret = tree.xpath('//li[contains(text(),"花")]')
# ret = tree.xpath('//a[starts-with(@class,"y")]/text()')
# ret = tree.xpath('//a[starts-with(@class,"y")]/@href')

ret = tree.xpath('//div[@id="xing"]//text()')
string = '-'.join(ret).replace('\n', '').replace('\t', '')

print(string)

本地測(cè)試

【注】獲取標(biāo)簽里面還有標(biāo)簽的內(nèi)容的時(shí)候
obj/text() 只能找到本標(biāo)簽里面的內(nèi)容,返回的都是列表茄袖,列表需要自己處理
obj//text() 標(biāo)簽里面所有的內(nèi)容操软,返回的是列表,列表需要處理

下載圖片例子

sc.chinaz.com
http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html 第一頁
http://sc.chinaz.com/tag_tupian/yazhoumeinv_2.html 第二頁

from lxml import etree
import time
import urllib.request
import urllib.parse
import os

def handle_request(url, url_er, page):
    if page == 1:
        url = url
    else:
        url = url_er.format(page)
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    return urllib.request.Request(url=url, headers=headers)

def parse_content(content):
    # 生成tree對(duì)象
    tree = etree.HTML(content)
    # 寫xpath宪祥,來獲取所有的圖片的image_src
    image_src_list = tree.xpath('//div[@id="container"]//img/@src2')
    image_alt_list = tree.xpath('//div[@id="container"]//img/@alt')
    # print(image_src_list)
    # print(len(image_src_list))
    for image_src in image_src_list:
        dirname = 'meinv'
        if not os.path.exists(dirname):
            os.mkdir(dirname)
        filename = image_alt_list[image_src_list.index(image_src)]
        suffix = image_src.split('.')[-1]
        filename = filename + '.' + suffix
        filepath = os.path.join(dirname, filename)
        print('正在下載%s聂薪。。蝗羊。席吴。哮翘。匙姜。' % filename)
        urllib.request.urlretrieve(image_src, filepath)
        print('結(jié)束下載%s' % filename)
        time.sleep(2)

def main():
    start_page = int(input('請(qǐng)輸入起始頁碼:'))
    end_page = int(input('請(qǐng)輸入結(jié)束頁碼:'))
    url = 'http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html'
    url_er = 'http://sc.chinaz.com/tag_tupian/yazhoumeinv_{}.html'
    for page in range(start_page, end_page + 1):
        print('正在下載第%s頁厂汗。。涯呻。凉驻。。复罐。' % page)
        request = handle_request(url, url_er, page)
        content = urllib.request.urlopen(request).read().decode('utf8')
        # 解析內(nèi)容函數(shù)
        parse_content(content)
        print('結(jié)束下載第%s頁' % page)
        time.sleep(2)

if __name__ == '__main__':
    main()

懶加載技術(shù)

只顯示可視區(qū)內(nèi)的圖片涝登,不再可視區(qū)內(nèi)的不顯示,等用戶滾動(dòng)滾動(dòng)條效诅,圖片呈現(xiàn)在可視區(qū)的時(shí)候在顯示
如何實(shí)現(xiàn)的胀滚?

<img src='xxx'>
<img src2='xxx'>  => 出現(xiàn)在可視區(qū)趟济,js動(dòng)態(tài)修改為  <img src='xxx'>
data-original=xxx
class='lazy'
data-src='xxx'

json處理

  • 獲取豆瓣電影的json數(shù)據(jù)寫入txt

import json
import urllib.request
import urllib.parse

url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=20&limit=20'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers)

content = urllib.request.urlopen(request).read().decode('utf8')

# print(content)
# 將json格式數(shù)據(jù)轉(zhuǎn)化為python對(duì)象
obj = json.loads(content)

# print(type(obj))
# 現(xiàn)在的obj是一個(gè)列表,列表里面都是字典
lt = []
# 遍歷列表咽笼,依次提取每一個(gè)字典里面的電影的名字和評(píng)分
for movie in obj:
    title = movie['title']
    score = movie['score']
    # movie['xixi']['hehe']['haha'][0]['lala']
    image_url = movie['cover_url']
    item = {
        '電影名字': title,
        '電影評(píng)分': score,
        '電影海報(bào)': image_url
    }
    lt.append(item)

string = json.dumps(lt, ensure_ascii=False)
with open('movie1.txt', 'w', encoding='utf8') as fp:
    fp.write(string)

2顷编、jsonpath

jsonpath是用來解析json數(shù)據(jù)的

格式: {} [] "" , :
python如何解析json格式

(1)自帶數(shù)據(jù)類型進(jìn)行解析

import json
json.dumps() : 將python對(duì)象轉(zhuǎn)化為json格式字符串
ensure_ascii=False  寫入文件中文顯示
json.loads() : 將json格式字符串轉(zhuǎn)化為python對(duì)象

(2)jsonpath解析(了解)

pip install jsonpath

http://blog.csdn.net/luxideyao/article/details/77802389
/ $ 根元素
. @ 當(dāng)前元素
/ . 層級(jí)分隔符
// .. 任意位置查找

  • jsonpath使用規(guī)則
import json
import jsonpath

fp = open('book.json', 'r', encoding='utf8')
string = fp.read()
fp.close()

# 將json格式字符串轉(zhuǎn)化為python對(duì)象
obj = json.loads(string)

# 使用jsonpath
# 查找所有book的author節(jié)點(diǎn)內(nèi)容
# ret = jsonpath.jsonpath(obj, '$.store.book[*].author')

# 從根下面開始找所有的author
ret = jsonpath.jsonpath(obj, '$..author')

# 查找store下面的所有節(jié)點(diǎn)
ret = jsonpath.jsonpath(obj, '$.store.*')

# 查找store下面的所有price節(jié)點(diǎn)
ret = jsonpath.jsonpath(obj, '$.store..price')

# 查找第三本book
ret = jsonpath.jsonpath(obj, '$..book[2]')

# 查找最后一本書籍
ret = jsonpath.jsonpath(obj, '$..book[(@.length-1)]')
print(ret)

淘寶評(píng)論---實(shí)戰(zhàn)

用戶頭像,用戶昵稱,評(píng)論內(nèi)容,評(píng)論圖片,評(píng)論時(shí)間,手機(jī)信息
https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983&currentPageNum=3&pageSize=20

import json
import jsonpath
import urllib.request
import urllib.parse
import time

# 用來存放所有的評(píng)論信息
items = []

def handle_request(page, url):
    url = url.format(page)
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    return urllib.request.Request(url=url, headers=headers)

def parse_content(content):
    # 如何解析content
    # 處理content,將其轉(zhuǎn)化為合法的json格式字符串
    content = content.strip('() \n\t\r')
    # print(content)
    obj = json.loads(content)
    # print(type(obj))
    # 提取出來所有的評(píng)論
    comments_list = obj['comments']
    # 遍歷列表剑刑,依次提取每一條評(píng)論的你要的信息
    for comment in comments_list:
        # 用戶頭像
        # avatar = comment['user']['avatar']
        avatar = jsonpath.jsonpath(comment, '$..avatar')[0]
        # 用戶昵稱
        nick = comment['user']['nick']
        # 評(píng)論內(nèi)容
        neirong = comment['content']
        # 圖片
        photos_list = comment['photos']
        photos = []
        for photo in photos_list:
            # 獲取小圖
            little_image = photo['thumbnail']
            # 獲取大圖
            big_image = photo['url']
            photos.append((little_image, big_image))
        # 時(shí)間
        ping_time = comment['date']
        # 手機(jī)信息
        info = jsonpath.jsonpath(comment, '$..sku')[0]
        
        item = {
            '用戶頭像': avatar,
            '用戶昵稱': nick,
            '評(píng)論內(nèi)容': neirong,
            '曬圖': photos,
            '評(píng)論時(shí)間': ping_time,
            '手機(jī)信息': info,
        }
        items.append(item)

def main():
    url = 'https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983&currentPageNum={}&pageSize=20'
    start_page = int(input('請(qǐng)輸入起始頁碼:'))
    end_page = int(input('請(qǐng)輸入結(jié)束頁碼:'))
    for page in range(start_page, end_page + 1):
    # for page in range(1, 2):
        print('正在爬取第%s頁......' % page)
        request = handle_request(page, url)
        content = urllib.request.urlopen(request).read().decode('utf8')
        parse_content(content)
        print('結(jié)束爬取第%s頁......' % page)
        time.sleep(2)

    # 爬取完畢, 寫入到文件中
    string = json.dumps(items, ensure_ascii=False)
    with open('taobao.json', 'w', encoding='utf8') as fp:
        fp.write(string)

if __name__ == '__main__':
    main()

3媳纬、selenium+phantomjs

http://chromedriver.storage.googleapis.com/index.html
http://blog.csdn.net/huilan_same/article/details/51896672

day06-爬蟲6

1、selenium+phantomjs

selenium是什麼施掏?

是一個(gè)瀏覽器自動(dòng)化測(cè)試工具钮惠,自動(dòng)化就是通過代碼操作瀏覽器,讓瀏覽器自動(dòng)的做一些操作七芭,是python的第三方庫素挽,需要安裝才能使用

pip install selenium

谷歌驅(qū)動(dòng)下載地址

http://chromedriver.storage.googleapis.com/index.html

驅(qū)動(dòng)和瀏覽器版本關(guān)系映射表

http://blog.csdn.net/huilan_same/article/details/51896672

selenium 操作谷歌瀏覽器

需要有一個(gè)谷歌瀏覽器的驅(qū)動(dòng),然后操作這個(gè)驅(qū)動(dòng)

from selenium import webdriver
import time

# 根據(jù)webdriver里面的類去創(chuàng)建一個(gè)谷歌瀏覽器對(duì)象
path = r'C:\Users\ZBLi\Desktop\1805\day06\ziliao\chromedriver.exe'
browser = webdriver.Chrome(path)

# 再往下狸驳,操作瀏覽器就是操作對(duì)象
# 打開百度
url = 'http://www.baidu.com/'
browser.get(url)
time.sleep(2)

# 查找百度輸入框
my_input = browser.find_element_by_id('kw')
# 寫內(nèi)容
my_input.send_keys('清純美女')
time.sleep(2)

# 查找按鈕框
button = browser.find_element_by_id('su')
button.click()

time.sleep(3)

# 查找陽光美女鏈接
href = browser.find_elements_by_xpath('//div[@class="op-img-covers-divide-high"][2]/a[2]')[0]
href.click()
time.sleep(3)

# 推出瀏覽器
browser.quit()

find_element_by_id 根據(jù)id找固定的節(jié)點(diǎn)
find_elements_by_name 根據(jù)name找節(jié)點(diǎn)
find_elements_by_xpath 根據(jù)xpath查找
find_elements_by_tag_name 根據(jù)標(biāo)簽名查找
find_elements_by_class_name 根據(jù)類名查找
find_elements_by_css_selector 根據(jù)選擇器查找
find_elements_by_link_text 根據(jù)鏈接內(nèi)容查找

作用在哪预明?

讓selenium操作的是phantomjs

phantomjs是什麼?

就是一款瀏覽器耙箍,無界面的瀏覽器撰糠,具有瀏覽器的功能,html\css\js這些文件瀏覽器可以直接執(zhí)行究西。
我們關(guān)注的就是phantomjs可以執(zhí)行js文件的功能窗慎,在爬取網(wǎng)站的時(shí)候,經(jīng)常碰見動(dòng)態(tài)加載數(shù)據(jù)的過程卤材。js DOM,解決方法兩種

(1)抓接口峦失,拿出來接口發(fā)送請(qǐng)求扇丛,解析即可
(2)讓瀏覽器直接執(zhí)行js,然后我要執(zhí)行js之后的網(wǎng)頁代碼尉辑,selenium+phantomjs帆精,終極解決方案,大招隧魄,缺點(diǎn):發(fā)請(qǐng)求之后要有停頓

操作phantomjs

from selenium import webdriver
import time

path = r'C:\Users\ZBLi\Desktop\1805\day06\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe'
browser = webdriver.PhantomJS(path)

browser.get('http://www.baidu.com/')
time.sleep(3)

# 拍照片卓练,記錄走到哪了
browser.save_screenshot(r'tupian\baidu1.png')

browser.find_element_by_id('kw').send_keys('美女')
time.sleep(2)
browser.find_element_by_id('su').click()
time.sleep(3)

browser.save_screenshot(r'tupian\baidu2.png')

browser.quit()

代碼中模擬滾動(dòng)條滾動(dòng)到底部

js = 'document.body.scrollTop=10000'
browser.execute_script(js)

from selenium import webdriver
import time

path = r'C:\Users\ZBLi\Desktop\1805\day06\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe'
browser = webdriver.PhantomJS(path)

url = 'https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action='
browser.get(url)
time.sleep(3)
browser.save_screenshot(r'tupian\douban1.png')

# 執(zhí)行一句js代碼即可
# for x in range(1, 6):
#   js = 'document.body.scrollTop=10000'
#   browser.execute_script(js)
#   time.sleep(3)
#   browser.save_screenshot(r'tupian\douban2.png')

js = 'document.body.scrollTop=10000'
browser.execute_script(js)
time.sleep(3)

# 獲取執(zhí)行js之后的網(wǎng)頁代碼
with open(r'tupian\douban.html', 'w', encoding='utf8') as fp:
    fp.write(browser.page_source)

# 往下就可以通過bs或者xpath來解析網(wǎng)頁內(nèi)容了

# 模擬點(diǎn)擊加載更多,就是通過browser找到那個(gè)按鈕购啄,讓按鈕執(zhí)行click方法即可

browser.quit()

獲取頁面的執(zhí)行js之后的代碼

    browser.page_source

2襟企、Headless Chrome

是什麼?
無頭的谷歌瀏覽器-無界面的谷歌瀏覽器狮含,phantomjs現(xiàn)在已經(jīng)沒人維護(hù)了顽悼,

要求:windows(60+以上)曼振、linux(59+以上)

from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
from selenium import webdriver

import time

from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

path = r'C:\Users\ZBLi\Desktop\1805\day06\ziliao\chromedriver.exe'
browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)

browser.get('http://www.baidu.com/')
time.sleep(2)

browser.save_screenshot(r'tupian\baidu3.png')

browser.quit()
  • 當(dāng)然:不僅谷歌有無界面模式,火狐也有蔚龙,ie也有冰评,phantomjs

3、requests

是什麼木羹?

  • 是一個(gè)第三方庫甲雅,這個(gè)庫和urllib是一樣的,就是模擬瀏覽器發(fā)送http請(qǐng)求的坑填,requests是對(duì)urllib的一層封裝务荆,所以提供的接口更加的人性化

詳請(qǐng)地址

http://docs.python-requests.org/zh_CN/latest/index.html

安裝方式

pip install requests

get\帶參數(shù)的get

data是一個(gè)參數(shù)字典
r = requests.get(url=url, params=data)
響應(yīng)對(duì)象r

r.text 字符串格式內(nèi)容
r.content 字節(jié)格式內(nèi)容
r.headers 響應(yīng)頭部
r.url 請(qǐng)求url
r.status_code 狀態(tài)碼


import requests

'''
url = 'http://www.baidu.com/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

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

# r是響應(yīng)對(duì)象
# 網(wǎng)頁的字符串內(nèi)容
# print(r.text)
# 字節(jié)內(nèi)容
# print(r.content)
# 獲取網(wǎng)頁的url
# print(r.url)
# 獲取響應(yīng)頭部
# print(r.headers)
# 獲取狀態(tài)碼
# print(r.status_code)

url = 'https://www.baidu.com/s?'
data = {
    'ie': 'utf8',
    'wd': '周杰倫'
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

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

with open(r'tupian\zhou.html', 'wb') as fp:
    fp.write(r.content)

post

必應(yīng)翻譯

data是參數(shù)字典
r = requests.post(url=url, data=data)

import requests

post_url = 'https://cn.bing.com/ttranslationlookup?&IG=5C360E60322D4FA4865EEBCF710B93B6&IID=translator.5036.2'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

fromdata = {
    'from': 'zh-CHS',
    'to': 'en',
    'text': '皇上',
}

r = requests.post(url=post_url, data=fromdata, headers=headers)

print(r.text)

會(huì)話

登錄,人人網(wǎng)---獲取保存cooike

s = requests.Session()
s.post()
s.get()

import requests

# 使用會(huì)話技術(shù)穷遂,首先創(chuàng)建一個(gè)會(huì)話
# 往下所有操作函匕,使用s進(jìn)行發(fā)送   s.post  s.get
s = requests.Session()

post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2018621432232'
data = {
    'email':'17701256561',
    'icode':'',
    'origURL':'http://www.renren.com/home',
    'domain':'renren.com',
    'key_id':'1',
    'captcha_type':'web_login',
    'password':'bd20fe8cf1541a10558676a6eeccb4a1a786cfc09823ddd69d5bbaafc7060292',
    'rkey':'227f4ceb2f44827f9de8296ca1ef1c3f',
    'f':'https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DaovDobnt13PO-vgvw1r-eSnSe_QNvNGtexiQFzyME-a%26wd%3D%26eqid%3Db5d58b1e000297f4000000025b4d88e3',
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

r = s.post(url=post_url, headers=headers, data=data)

# print(r.text)

url = 'http://www.renren.com/960481378/profile'

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

with open('renren.html', 'wb') as fp:
    fp.write(r.content)
公交爬取
import requests
from lxml import etree
import re
import json
import time

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

def parse_first_page(url):
    r = requests.get(url=url, headers=headers)
    # 生成一個(gè)tree對(duì)象
    tree = etree.HTML(r.text)
    # 通過tree對(duì)象查找所有的數(shù)字、字母鏈接
    number_href_list = tree.xpath('//div[@class="bus_kt_r1"]/a/@href')
    char_href_list = tree.xpath('//div[@class="bus_kt_r2"]/a/@href')
    return number_href_list + char_href_list

def parse_second_page(url, all_href, fp):
    # 為了拼接完整的url蚪黑,先將右邊的 / 干掉
    url = url.rstrip('/')
    for href in all_href:
        href = url + href
        r = requests.get(href, headers=headers)
        tree = etree.HTML(r.text)
        # 解析盅惜,獲取所有的公交href信息
        bus_href_list = tree.xpath('//div[@id="con_site_1"]/a/@href')
        bus_name_list = tree.xpath('//div[@id="con_site_1"]/a/text()')
        # print(bus_href_list)
        # exit()
        # 向列表中的url依次發(fā)送請(qǐng)求,解析內(nèi)容
        parse_third_page(url, bus_href_list, bus_name_list, fp)

def parse_third_page(url, bus_href_list, bus_name_list, fp):
    for bus_href in bus_href_list:
        title = bus_name_list[bus_href_list.index(bus_href)]
        print('正在爬取%s......' % title)
        # 拼接完整的url
        bus_href = url + bus_href
        # 向每一路公交的詳情頁發(fā)送請(qǐng)求
        r = requests.get(url=bus_href, headers=headers)
        # 在下面的函數(shù)中忌穿,解析每一路公交的詳細(xì)信息
        parse_content(r.text, fp)
        print('結(jié)束爬取%s' % title)
        time.sleep(1)

def parse_content(content, fp):
    tree = etree.HTML(content)
    # 獲取線路名稱
    name = tree.xpath('//div[@class="bus_i_t1"]/h1/text()')[0]
    # 獲取運(yùn)行時(shí)間
    runtime = tree.xpath('//div[@class="bus_i_content"]/p[1]/text()')[0]
    # 獲取票價(jià)信息
    price = tree.xpath('//div[@class="bus_i_content"]/p[2]/text()')[0]
    # 公交公司
    try:
        company = tree.xpath('//div[@class="bus_i_content"]/p[3]/a/text()')[0]
    except Exception as e:
        company = ''
    
    # 更新時(shí)間
    gxsj = tree.xpath('//div[@class="bus_i_content"]/p[last()]/text()')[0]
    # 獲取公交路線長(zhǎng)度
    try:
        length = tree.xpath('//div[@class="bus_label "]/p/text()')[0]
        pattern = re.compile(r'\d+\.\d+')
        ret = pattern.search(length)
        length = ret.group()
    except Exception as e:
        length = ''
    

    total_list = tree.xpath('//span[@class="bus_line_no"]/text()')
    # 獲取上行總站數(shù), 使用正則將總站數(shù)拿走
    pattern = re.compile(r'\d+')
    up_total = total_list[0]
    up_total = pattern.search(up_total).group()
    # 獲取下行總站數(shù)
    try:
        down_total = total_list[1]
        down_total = pattern.search(down_total).group()
    except Exception as e:
        down_total = ''
    
    # 獲取上行的公交站牌信息
    up_site_name = tree.xpath('//div[@class="bus_line_site "][1]//a/text()')

    # 獲取下行的公交站牌信息
    try:
        down_site_name = tree.xpath('//div[@class="bus_line_site "][2]//a/text()')
    except Exception as e:
        down_site_name = []
    
    

    # 將公交的詳細(xì)信息保存到字典中
    item = {
        '線路名稱': name,
        '運(yùn)行時(shí)間': runtime,
        '票價(jià)信息': price,
        '公交公司': company,
        '更新時(shí)間': gxsj,
        '線路長(zhǎng)度': length,
        '上行站數(shù)': up_total,
        '上行站牌': up_site_name,
        '下行站數(shù)': down_total,
        '下行站牌': down_site_name,
    }
    string = json.dumps(item, ensure_ascii=False)
    fp.write(string + '\n')


def main():
    # 打開文件
    fp = open('北京公交路線.txt', 'w', encoding='utf8')
    url = 'http://beijing.8684.cn/'
    # 獲取所有的數(shù)字抒寂、字母鏈接
    all_href = parse_first_page(url)
    # 遍歷列表,依次發(fā)送請(qǐng)求掠剑,解析二級(jí)頁面
    parse_second_page(url, all_href, fp)
    fp.close()

if __name__ == '__main__':
    main()

4屈芜、登錄---驗(yàn)證碼

驗(yàn)證碼:

(1)將驗(yàn)證碼下載到本地,讓用戶手動(dòng)輸入
(2)使用軟件識(shí)別朴译,效率不高
(3)使用打碼平臺(tái)井佑,識(shí)別率高
import requests

# 搞一個(gè)會(huì)話
s = requests.Session()

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}

# 先將驗(yàn)證碼下載到本地
get_url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
r = s.get(get_url, headers=headers)

# 需要向圖片src發(fā)送請(qǐng)求,將驗(yàn)證碼下載到本地
image_src = 'https://so.gushiwen.org/RandCode.ashx'
r = s.get(image_src, headers=headers)
with open('code.png', 'wb') as fp:
    fp.write(r.content)


code = input('請(qǐng)輸入驗(yàn)證碼:')

post_url = 'https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
data = {
    '__VIEWSTATE': 'BvBAwAIKh29BShbC/yKMDsjiElxi+d4wdH3pR2dacgsifqK0rmUzL4Mc9YzHGDc6P6rqB4wMZ39uRj2MpaaSjQtarGnIo6qf1djLGa75XLo/S4b65Uhv2TETKt0=',
    '__VIEWSTATEGENERATOR':'C93BE1AE',
    'from': 'http://so.gushiwen.org/user/collect.aspx',
    'email': '1090509990@qq.com',
    'pwd': '123456',
    'code': code,
    'denglu': '登錄',
}

r = s.post(post_url, headers=headers, data=data)

print(r.text)

多進(jìn)程

多任務(wù):生活中來看眠寿,就是多個(gè)任務(wù)同時(shí)進(jìn)行躬翁,喝酒聊天,開車盯拱,手腳并用盒发,唱歌跳舞
電腦中:錄屏、sublime狡逢、vnc服務(wù)端宁舰、瀏覽器打開等
代碼中:實(shí)現(xiàn)多任務(wù),多進(jìn)程奢浑、多線程
進(jìn)程:電腦中蛮艰,每一個(gè)軟件啟動(dòng)起來都是一個(gè)進(jìn)程,
代碼中:沒有運(yùn)行的時(shí)候稱之為程序殷费,運(yùn)行起來之后就是一個(gè)進(jìn)程
多進(jìn)程:進(jìn)程只有一個(gè)印荔,稱之為主進(jìn)程低葫,子進(jìn)程,要實(shí)現(xiàn)兩個(gè)函數(shù)同時(shí)執(zhí)行仍律,就要通過主進(jìn)程來創(chuàng)建子進(jìn)程
操作系統(tǒng)實(shí)現(xiàn)嘿悬,只是在進(jìn)程之間來回切換,切換的非乘快善涨,看著像同時(shí)執(zhí)行一樣

如何實(shí)現(xiàn)?

面向過程:(process)

p = Process(target=xxx, name=xxx, args=(xxx,))
target: 進(jìn)程啟動(dòng)之后要執(zhí)行的函數(shù)
name: 給進(jìn)程起個(gè)名字
args: 給子進(jìn)程傳遞的參數(shù)草则,是一個(gè)元組
p.start() 啟動(dòng)進(jìn)程
p.join() 讓主進(jìn)程等待子進(jìn)程結(jié)束
os.getpid() 獲取當(dāng)前進(jìn)程id號(hào)
os.getppid() 獲取父進(jìn)程的id號(hào)

from multiprocessing import Process
import time
import os

# 想讓子進(jìn)程1執(zhí)行sing函數(shù)
def sing(a):
    print('接受的參數(shù)為%s' % a)
    # 進(jìn)程id號(hào)
    print('進(jìn)程-%s-開始運(yùn)行' % os.getpid())
    print('父進(jìn)程為%s' % os.getppid())
    for x in range(1, 5):
        print('我在唱小情歌')
        time.sleep(1)

# 想讓子進(jìn)程2執(zhí)行dance函數(shù)
def dance(a):
    print('進(jìn)程-%s-開始運(yùn)行' % os.getpid())
    print('父進(jìn)程為%s' % os.getppid())
    for x in range(1, 5):
        print('我在跳鋼管舞')
        time.sleep(1)

def main():
    # 主進(jìn)程
    print('主進(jìn)程id號(hào)為%s' % os.getpid())
    a = '青花瓷'
    # 創(chuàng)建進(jìn)程
    p_sing = Process(target=sing, name='唱歌', args=(a,))
    p_dance = Process(target=dance, name='跳舞', args=(a,))
    
    # 啟動(dòng)進(jìn)程
    p_sing.start()
    p_dance.start()

    # 獲取進(jìn)程名字
    print(p_sing.name)
    print(p_dance.name)

    # 因?yàn)橹鬟M(jìn)程中有子進(jìn)程的信息钢拧,所以主進(jìn)程必須等子進(jìn)程結(jié)束之后再結(jié)束
    p_sing.join()
    p_dance.join()

    print('主進(jìn)程結(jié)束')

if __name__ == '__main__':
    main()

面向?qū)ο螅?/h4>
from multiprocessing import Process
import time

class SingProcess(Process):
    def __init__(self, a):
        # 如果要重寫構(gòu)造方法,一定得手動(dòng)調(diào)用父類的構(gòu)造方法
        super().__init__()
        self.a = a

    def run(self):
        print('傳遞的參數(shù)為%s' % self.a)
        for x in range(1, 5):
            print('我在唱小情歌')
            time.sleep(1)

class DanceProcess(Process):
    def run(self):
        for x in range(1, 5):
            print('我在跳鋼管舞')
            time.sleep(1)
        

def main():
    a = '現(xiàn)在很多老歌手為什么不唱歌了'
    p_sing = SingProcess(a)
    # 啟動(dòng)進(jìn)程炕横,進(jìn)程啟動(dòng)之后默認(rèn)執(zhí)行類里面的run方法
    p_sing.start()

    # p_dance = DanceProcess()
    # p_dance.start()

    p_sing.join()
    # p_dance.join()
    print('主進(jìn)程結(jié)束')

if __name__ == '__main__':
    main()

多進(jìn)程拷貝源内,拷貝文件夾,假如文件夾里面只有文件份殿。假如有100個(gè)文件膜钓,那么拷貝的時(shí)候先拷貝第一個(gè),然后第二個(gè)卿嘲,然后第三個(gè)====
拷貝一個(gè)文件就是一個(gè)任務(wù)颂斜,那一共100文件,那難道要開辟100個(gè)進(jìn)程嗎拾枣?
進(jìn)程并不是越多越好沃疮,切換占用的時(shí)間越大

練習(xí):多進(jìn)程拷貝
拷貝之前記錄時(shí)間戳,拷貝之后記錄時(shí)間戳梅肤,計(jì)算拷貝的時(shí)間
多進(jìn)程拷貝也是一樣司蔬,哪個(gè)時(shí)間短
引入進(jìn)程池,規(guī)定能創(chuàng)建幾個(gè)進(jìn)程凭语,來了任務(wù)葱她,5個(gè)進(jìn)程

進(jìn)程之間是否共享全局變量

全局變量
進(jìn)程之間是否共享全局變量,不共享
每一個(gè)進(jìn)程都是單獨(dú)的代碼

from multiprocessing import Process
import os
import time

count = 100

# 該進(jìn)程用來修改全局變量的值
def change():
    global count
    count += 100
    print('進(jìn)程%s修改后的值為%s' % (os.getpid(), count))

# 該進(jìn)程用來讀取全局變量的值
def read():
    print('進(jìn)程%s讀取的值為%s' % (os.getpid(), count))

def test(c):
    a = 100
    if c == 'hello':
        a += 100
        time.sleep(2)
        print('進(jìn)程%s修改a的值為%s' % (os.getpid(), a))
    else:
        time.sleep(5)
        print('進(jìn)程%s讀取a的值為%s' % (os.getpid(), a))

def main():
    '''
    p1 = Process(target=change)
    p1.start()
    time.sleep(2)

    p2 = Process(target=read)
    p2.start()
    '''
    a = 'hello'
    b = 'world'
    p1 = Process(target=test, args=(a, ))
    p2 = Process(target=test, args=(b, ))
    p1.start()
    p2.start()

    p1.join()
    p2.join()

if __name__ == '__main__':
    main()

進(jìn)程池

from multiprocessing import Process
from multiprocessing import Pool
import os
import time

def test(name):
    print('任務(wù)%s正在運(yùn)行,進(jìn)程id號(hào)為%s' % (name, os.getpid()))
    time.sleep(2)

def main():
    # 創(chuàng)建一個(gè)進(jìn)程池對(duì)象
    po = Pool(3)

    # 給進(jìn)程池添加任務(wù)
    lt = ['關(guān)羽', '趙云', '張飛', '馬超', '黃忠', '呂布', '孫策', '大喬']
    for name in lt:
        po.apply_async(test, args=(name, ))

    # 進(jìn)程池使用完畢之后似扔,關(guān)閉
    po.close()
    # 讓主進(jìn)程等待結(jié)束
    po.join()
    print('主進(jìn)程、進(jìn)程池全部結(jié)束')

if __name__ == '__main__':
    main()

多線程

線程:比如qq搓谆。比如暴風(fēng)影音炒辉,比如word
可以同時(shí)語音、同時(shí)視頻泉手、同時(shí)聊天黔寇,多線程
暴風(fēng)影音,視頻播放斩萌、音頻播放缝裤,多線程
word屏轰,打字,拼寫檢查憋飞,等霎苗,多線程
多任務(wù)的實(shí)現(xiàn):多進(jìn)程、多線程

主進(jìn)程-子進(jìn)程1-子進(jìn)程2
特點(diǎn):進(jìn)程之間沒有關(guān)系榛做,如果一個(gè)進(jìn)程掛了唁盏,不影響其它子進(jìn)程

進(jìn)程-主線程-子線程1-子線程2
特點(diǎn):線程之間有關(guān)系,如果一個(gè)線程掛了检眯,整個(gè)進(jìn)程就掛了

實(shí)現(xiàn)方式:(thread)

面向過程

t = Thread(target=xxx, name=xxx, args=(xxx,))
target: 線程啟動(dòng)之后要執(zhí)行的函數(shù)
name: 線程的名字
args: 給線程傳遞的參數(shù)
t.start(): 啟動(dòng)線程
t.join(): 讓主線程等待子線程結(jié)束
threading.current_thread().name : 獲取線程名字

import threading
import time

def sing(song):
    print('傳遞過來的參數(shù)為%s' % song)
    print('獲取線程的名字為%s' % threading.current_thread().name)
    for x in range(1, 5):
        print('我在唱老情歌')
        time.sleep(1)

def dance():
    for x in range(1, 5):
        print('我在跳廣場(chǎng)舞')
        time.sleep(1)

def main():
    a = '廣島之戀'
    # 這是一個(gè)進(jìn)程厘擂,進(jìn)程里面有一個(gè)主線程,然后主線程創(chuàng)建子線程1(唱歌)锰瘸,子線程2(跳舞)
    t_sing = threading.Thread(target=sing, name='唱歌', args=(a, ))
    t_dance = threading.Thread(target=dance, name='跳舞')

    # 啟動(dòng)線程
    t_sing.start()
    t_dance.start()

    t_sing.join()
    t_dance.join()

    print('主線程刽严、子線程同時(shí)結(jié)束')

if __name__ == '__main__':
    main()

面向?qū)ο?/h3>
import threading
import time

# 滕王閣序  王勃
# 命硬
# 沁園春-雪
# 出師表

class MyThread(threading.Thread):
    def __init__(self, a):
        super().__init__()
        self.a = a

    def run(self):
        print('傳遞過來的參數(shù)為%s' % self.a)
        for x in range(1, 5):
            print('鳳凰臺(tái)上鳳凰游,鳳去臺(tái)空江自流')
            time.sleep(1)

def main():
    a = '落霞與孤鶩齊飛,秋水共長(zhǎng)天一色'
    t = MyThread(a)
    t.start()
    t.join()

    print('主線程避凝、子線程全部結(jié)束')

if __name__ == '__main__':
    main()

是否共享

全局變量
共享全局變量
局部變量
不共享局部變量
線程安全問題
線程之間可以共享全局變量

import threading
import os
import time

count = 100

# 該線程用來修改全局變量的值
def change():
    global count
    count += 100
    print('線程%s修改后的值為%s' % (threading.current_thread().name, count))

# 該線程用來讀取全局變量的值
def read():
    print('線程%s讀取的值為%s' % (threading.current_thread().name, count))


def test():
    a = 100
    name = threading.current_thread().name
    if name == 'lala':
        a += 100
        time.sleep(2)
        print('線程%s修改a的值為%s' % (name, a))
    else:
        time.sleep(5)
        print('線程讀取a的值為%s' % a)

def main():
    '''
    t1 = threading.Thread(target=change, name='修改thread')
    t1.start()
    time.sleep(2)

    t2 = threading.Thread(target=read, name='讀取thread')
    t2.start()
    '''
    t1 = threading.Thread(target=test, name='lala')
    t2 = threading.Thread(target=test)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

if __name__ == '__main__':
    main()

加鎖

加鎖

lock.acquire()

釋放鎖

lock.release()

import threading
import time

count = 100
# 創(chuàng)建一把鎖
lock = threading.Lock()

def test(number):
    start = time.time()
    # 在這里面修改count的值
    global count
    for x in range(1, 10000000):
        # 加鎖
        lock.acquire()
        count += number
        count -= number
        # 釋放鎖
        lock.release()
    end = time.time()
    # 上廁所舞萄,大號(hào),如何解決恕曲,加鎖
    # 用之前鹏氧,加鎖,用完之后佩谣,釋放鎖
    # 犧牲了效率了

    print('循環(huán)計(jì)算的時(shí)間為%s' % (start - end))

def main():
    t1 = threading.Thread(target=test, args=(3, ))
    t2 = threading.Thread(target=test, args=(5, ))
    t2.start()
    t1.start()
    t1.join()
    t2.join()

    print('主線程中打印的count的值為%s' % count)

if __name__ == '__main__':
    main()

隊(duì)列

隊(duì)列:買火車票把还,電動(dòng)三輪,特點(diǎn):先進(jìn)先出
用在哪茸俭?

線程之間使用隊(duì)列進(jìn)行交互吊履,讓線程解耦合,生產(chǎn)者-消費(fèi)者模型

線程1-生產(chǎn)數(shù)據(jù)

交互渠道:隊(duì)列

線程2-消費(fèi)數(shù)據(jù)
while 1:
生產(chǎn)數(shù)據(jù)
消費(fèi)數(shù)據(jù)

隊(duì)列使用:

            from queue import Queue
    q = Queue(5)
    q.put()         添加元素
    q.put(False)    如果隊(duì)列已滿调鬓,添加元素立即拋出異常
    q.put(True, 5)  如果隊(duì)列已滿艇炎,添加元素5s之后拋出異常
    q.get()         獲取元素
    q.get(False)    如果隊(duì)列為空,獲取元素立即拋出異常
    q.get(True, 5)  如果隊(duì)列為空腾窝,獲取元素5s之后拋出異常
    q.empty()       隊(duì)列是否為空
    q.full()        隊(duì)列是否已滿
    q.qsize()       隊(duì)列長(zhǎng)度
from queue import Queue

# 創(chuàng)建一個(gè)隊(duì)列
# 如果寫缀踪,代表隊(duì)列的長(zhǎng)度,如果不寫虹脯,隊(duì)列長(zhǎng)度無限
q = Queue(5)

print(q.empty())
print(q.full())
print(q.qsize())

# 向隊(duì)列中添加數(shù)據(jù)
q.put('吳彥祖')
q.put('岳云鵬')
q.put('王寶強(qiáng)')
q.put('黃渤')
q.put('劉德華')
print(q.empty())
print(q.full())
print(q.qsize())
# q.put('古天樂', True, 5)

# 從隊(duì)列中獲取數(shù)據(jù)
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get(True, 5))

多線程爬蟲

分析:
爬蟲里面如何分多線程驴娃,

循環(huán):
拼接url,發(fā)送請(qǐng)求循集,獲取響應(yīng)
解析響應(yīng)唇敞,保存到文件

涉及到:
采集線程,3個(gè)線程同時(shí)采集
解析線程,3個(gè)線程同時(shí)解析
頁碼隊(duì)列:里面是要爬取的頁碼數(shù)據(jù)
數(shù)據(jù)隊(duì)列:采集線程向隊(duì)列中添加數(shù)據(jù)
解析線程從隊(duì)列中獲取數(shù)據(jù)
保存到同一個(gè)文件中疆柔,鎖機(jī)制

import threading
from queue import Queue
import time
from lxml import etree
import requests
import json

class CrawlThread(threading.Thread):
    def __init__(self, name, page_queue, data_queue):
        super().__init__()
        self.name = name
        # 保存頁碼隊(duì)列
        self.page_queue = page_queue
        self.data_queue = data_queue
        # url
        self.url = 'http://www.fanjian.net/duanzi-{}'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
        }

    def run(self):
        print('%s線程開始啟動(dòng)' % self.name)
        # 這里面的思路是什么咒精?
        while 1:
            if self.page_queue.empty():
                break
            # 1、從頁碼隊(duì)列中獲取頁碼
            page = self.page_queue.get()
            # 2旷档、將url和頁碼進(jìn)行拼接
            url = self.url.format(page)
            # 3模叙、發(fā)送請(qǐng)求,獲取響應(yīng)
            r = requests.get(url=url, headers=self.headers)
            time.sleep(1)

            # 4彬犯、將響應(yīng)內(nèi)容放入到數(shù)據(jù)隊(duì)列中
            self.data_queue.put(r.text)
            
        print('%s線程結(jié)束' % self.name)

class ParseThread(threading.Thread):
    def __init__(self, name, data_queue, lock, fp):
        super().__init__()
        self.name = name
        # 保存數(shù)據(jù)隊(duì)列
        self.data_queue = data_queue

        self.lock = lock
        self.fp = fp

    def run(self):
        print('%s線程開始啟動(dòng)' % self.name)
        # 解析線程解析步驟
        while 1:

            if self.data_queue.empty():

                break
            # 1向楼、從數(shù)據(jù)隊(duì)列中取出一個(gè)數(shù)據(jù)
            content = self.data_queue.get()
            # 2、解析這個(gè)數(shù)據(jù)

            items = self.parse_content(content)
            # 3谐区、寫入到文件中
            string = json.dumps(items, ensure_ascii=False)
            # 加鎖
            self.lock.acquire()
            self.fp.write(string)
            # 釋放鎖
            self.lock.release()
        print('%s線程結(jié)束' % self.name)

    # 解析數(shù)據(jù)函數(shù)
    def parse_content(content):
        # 生成tree對(duì)象
        tree = etree.HTML(content)
        # 先找到所有的li標(biāo)簽
        li_list = tree.xpath('//li[@class="cont-item"]')
        items = []
        for oli in li_list:
            # 獲取頭像

            face = oli.xpath('.//div[@class="cont-list-reward"]//img/@data-src')[0]
            # 獲取名字
            name = oli.xpath('.//div[@class="cont-list-head"]/a/text()')[0]
            # 獲取內(nèi)容
            text = oli.xpath('.//div[@class="cont-list-main"]/p/text()')[0]
            # 獲取時(shí)間
            shijian = oli.xpath('.//div[@class="cont-list-info fc-gray"]/text()')[-1]
            item = {
                '頭像': face,
                '名字': name,
                '內(nèi)容': text,
                '時(shí)間': shijian,
            }

            # 將字典添加到列表中
            items.append(item)

        return items
        

def create_queue():
    page_queue = Queue()
    data_queue = Queue()
    # 向頁碼隊(duì)列中添加頁碼
    for page in range(1, 11):
        page_queue.put(page)
    return page_queue, data_queue

def main():
    # 做什么湖蜕?
    # 創(chuàng)建鎖
    lock = threading.Lock()
    # 打開文件
    fp = open('duanzi.txt', 'w', encoding='utf8')
    # 創(chuàng)建兩個(gè)隊(duì)列
    page_queue, data_queue = create_queue()
    # 創(chuàng)建采集、解析線程
    crawlname_list = ['采集線程1', '采集線程2', '采集線程3']
    parsename_list = ['解析線程1', '解析線程2', '解析線程3']
    # 列表宋列,用來保存所有的采集線程和解析線程
    t_crawl_list = []
    t_parse_list = []
    for crawlname in crawlname_list:
        t_crawl = CrawlThread(crawlname, page_queue, data_queue)
        t_crawl.start()
        # 將對(duì)應(yīng)的采集線程保存起來
        t_crawl_list.append(t_crawl)

    for parsename in parsename_list:
        t_parse = ParseThread(parsename, data_queue, lock, fp)
        # 將對(duì)應(yīng)的解析線程保存起來
        t_parse_list.append(t_parse)
        t_parse.start()

    # 讓主線程等待子線程結(jié)束之后再結(jié)束
    for t_crawl in t_crawl_list:
        t_crawl.join()
    for t_parse in t_parse_list:
        t_parse.join()

    fp.close()
    print('主線程昭抒、子線程全部結(jié)束')

if __name__ == '__main__':
    main()

# 留給大家了,為什么里面沒有寫數(shù)據(jù)呢炼杖?

自動(dòng)識(shí)別驗(yàn)證碼

(1)光學(xué)識(shí)別 OCR 其實(shí)就是一個(gè)軟件

  • 別對(duì)他期望太高灭返,識(shí)別率80% 90%
    *訓(xùn)練它
    代碼識(shí)別

pip install pytesseract
pip install pillow

轉(zhuǎn)化為灰度圖片

img = img.convert('L')
img.show()

二值化處理

threshold = 140
table = []
for i in range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)
out = img.point(table, '1')
out.show()

img = img.convert('RGB')
enhancer = ImageEnhance.Color(img)
enhancer = enhancer.enhance(0)
enhancer = ImageEnhance.Brightness(enhancer)
enhancer = enhancer.enhance(2)
enhancer = ImageEnhance.Contrast(enhancer)
enhancer = enhancer.enhance(8)
enhancer = ImageEnhance.Sharpness(enhancer)
img = enhancer.enhance(20)

實(shí)例代碼如下

import pytesseract
from PIL import Image
from PIL import ImageEnhance

def shibie(imagepath):
    img = Image.open(imagepath)

    img = img.convert('RGB')
    enhancer = ImageEnhance.Color(img)
    enhancer = enhancer.enhance(0)
    enhancer = ImageEnhance.Brightness(enhancer)
    enhancer = enhancer.enhance(2)
    enhancer = ImageEnhance.Contrast(enhancer)
    enhancer = enhancer.enhance(8)
    enhancer = ImageEnhance.Sharpness(enhancer)
    img = enhancer.enhance(20)

    # 轉(zhuǎn)化為灰度圖片
    img = img.convert('L')
    # img.show()

    # 二值化處理
    threshold = 140
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    out = img.point(table, '1')
    # out.show()

    img = img.convert('RGB')

    return pytesseract.image_to_string(img)
shibie('code.png')

打碼平臺(tái),專業(yè)坤邪,識(shí)別率高熙含,花錢

云打碼平臺(tái)使用

用戶注冊(cè)(充錢)、開發(fā)者注冊(cè)(創(chuàng)建應(yīng)用艇纺,使用應(yīng)用識(shí)別驗(yàn)證碼服務(wù))

import http.client, mimetypes, urllib, json, time, requests

######################################################################

class YDMHttp:

    apiurl = 'http://api.yundama.com/api.php'
    username = ''
    password = ''
    appid = ''
    appkey = ''

    def __init__(self, username, password, appid, appkey):
        self.username = username  
        self.password = password
        self.appid = str(appid)
        self.appkey = appkey

    def request(self, fields, files=[]):
        response = self.post_url(self.apiurl, fields, files)
        response = json.loads(response)
        return response
    
    def balance(self):
        data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['balance']
        else:
            return -9001
    
    def login(self):
        data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['uid']
        else:
            return -9001

    def upload(self, filename, codetype, timeout):
        data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
        file = {'file': filename}
        response = self.request(data, file)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['cid']
        else:
            return -9001

    def result(self, cid):
        data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid)}
        response = self.request(data)
        return response and response['text'] or ''

    def decode(self, filename, codetype, timeout):
        cid = self.upload(filename, codetype, timeout)
        if (cid > 0):
            for i in range(0, timeout):
                result = self.result(cid)
                if (result != ''):
                    return cid, result
                else:
                    time.sleep(1)
            return -3003, ''
        else:
            return cid, ''

    def report(self, cid):
        data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid), 'flag': '0'}
        response = self.request(data)
        if (response):
            return response['ret']
        else:
            return -9001

    def post_url(self, url, fields, files=[]):
        for key in files:
            files[key] = open(files[key], 'rb');
        res = requests.post(url, files=files, data=fields)
        return res.text

######################################################################

# 用戶名
# 普通賬號(hào)的用戶名
username    = ''

# 密碼
# 普通賬號(hào)的密碼
password    = ''                            

# 軟件ID怎静,開發(fā)者分成必要參數(shù)。登錄開發(fā)者后臺(tái)【我的軟件】獲得黔衡!
appid       =                                      

# 軟件密鑰蚓聘,開發(fā)者分成必要參數(shù)。登錄開發(fā)者后臺(tái)【我的軟件】獲得盟劫!
appkey      = ''    

# 圖片文件
filename    = './png/e6ay.png'                        

# 驗(yàn)證碼類型夜牡,# 例:1004表示4位字母數(shù)字,不同類型收費(fèi)不同侣签。請(qǐng)準(zhǔn)確填寫塘装,否則影響識(shí)別率。在此查詢所有類型 http://www.yundama.com/price.html
codetype    = 1004

# 超時(shí)時(shí)間影所,秒
timeout     = 60                                    

# 檢查
if (username == 'username'):
    print('請(qǐng)?jiān)O(shè)置好相關(guān)參數(shù)再測(cè)試')
else:
    # 初始化
    yundama = YDMHttp(username, password, appid, appkey)

    # 登陸云打碼
    uid = yundama.login();
    print('uid: %s' % uid)

    # 查詢余額
    balance = yundama.balance();
    print('balance: %s' % balance)

    # 開始識(shí)別氢哮,圖片路徑,驗(yàn)證碼類型ID型檀,超時(shí)時(shí)間(秒),識(shí)別結(jié)果
    cid, result = yundama.decode(filename, codetype, timeout);
    print('cid: %s, result: %s' % (cid, result))

######################################################################

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末听盖,一起剝皮案震驚了整個(gè)濱河市胀溺,隨后出現(xiàn)的幾起案子裂七,更是在濱河造成了極大的恐慌,老刑警劉巖仓坞,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件背零,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡无埃,警方通過查閱死者的電腦和手機(jī)徙瓶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫉称,“玉大人侦镇,你說我怎么就攤上這事≈模” “怎么了壳繁?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)荔棉。 經(jīng)常有香客問我闹炉,道長(zhǎng),這世上最難降的妖魔是什么润樱? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任渣触,我火速辦了婚禮,結(jié)果婚禮上壹若,老公的妹妹穿的比我還像新娘嗅钻。我一直安慰自己,他們只是感情好舌稀,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布啊犬。 她就那樣靜靜地躺著,像睡著了一般壁查。 火紅的嫁衣襯著肌膚如雪觉至。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天睡腿,我揣著相機(jī)與錄音语御,去河邊找鬼。 笑死席怪,一個(gè)胖子當(dāng)著我的面吹牛应闯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挂捻,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼碉纺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骨田,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤耿导,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后态贤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舱呻,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年悠汽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箱吕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柿冲,死狀恐怖茬高,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姻采,我是刑警寧澤雅采,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站慨亲,受9級(jí)特大地震影響婚瓜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刑棵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一巴刻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛉签,春花似錦胡陪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至片橡,卻和暖如春妈经,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捧书。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工吹泡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人经瓷。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓爆哑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親舆吮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揭朝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容