initial commit

This commit is contained in:
Matthieu Bessat 2023-02-19 12:10:12 +01:00
commit 5e6967def2
13 changed files with 586744 additions and 0 deletions

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# Linkedin posts scrapper

View file

@ -0,0 +1,15 @@
# scan the true content folder and recreate all the symbolic links
from os.path import basename
from pathlib import Path
SITE_BASE = "./janco_website"
MD_ORGANIZED_CONTENT_BASE = "./janco_website/true_content/posts"
MD_FLAT_CONTENT_BASE = "./janco_website/content/posts"
for path in Path(MD_ORGANIZED_CONTENT_BASE).rglob('*.md'):
bn = basename(path)
Path(MD_FLAT_CONTENT_BASE + '/' + bn).symlink_to('../../' + str(path.relative_to(SITE_BASE)))

112
gen_content.py Normal file
View file

@ -0,0 +1,112 @@
#se generate markdown that can be used with hugo
# A single JSON file that contains all the posts that we want to generate
# This file contains a JSON array with linkedin user profile posts
INP_FILE_PATH = "./out_posts_all_1.json"
# This file hold the current state of scrapping, what articles have been scrapped
STORAGE_FILE_PATH = "./posts_scrapping_state.json"
MD_ORGANIZED_CONTENT_BASE = "./janco_website/true_content/posts"
MD_FLAT_CONTENT_BASE = "./janco_website/content/posts"
import json
from urllib.parse import urljoin, urlparse
import uuid
import os
from typing import Optional
def slurp_file_and_parse(inp_file_path):
posts = []
with open(inp_file_path) as inp_file:
posts = json.loads(inp_file.read())
return posts
posts = slurp_file_and_parse(INP_FILE_PATH)
from pprint import pprint
from slugify import slugify
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Post:
id: int
title: str
created_at: datetime
content: str
original_url: str
@property
def slug(self) -> str:
return slugify(self.title)
ARTICLE_COMPONENT = "com.linkedin.voyager.feed.render.ArticleComponent"
global_count = 0
def parse_post(raw_post):
global global_count
def datetime_from_id(id: int):
# thanks to https://github.com/Ollie-Boyd/Linkedin-post-timestamp-extractor
epoch = (id & 0xffffffffff800000) >> 22
return datetime.utcfromtimestamp(epoch/1000)
entity_id = int(raw_post['entityUrn'].split("activity:")[1].split(',')[0])
original_url = next(filter(lambda x: x['actionType'] == "SHARE_VIA", raw_post['updateMetadata']['updateActions']['actions']))['url']
original_url = urljoin(original_url, urlparse(original_url).path)
created_at = datetime_from_id(entity_id)
global_count += 1
out_post = Post(
id=entity_id,
title=f"CHANGE_ME {global_count}",
content=raw_post['commentary']['text']['text'],
created_at=created_at.replace(microsecond=0),
original_url=original_url
# title=raw_post
)
# content_items = list(raw_post['content'].items())
components = list(raw_post['content'].keys()) if 'content' in raw_post else []
# the "content" key contains some other components like the com.linkedin.voyager.feed.render.ArticleComponent that indicate there is an article (linked) attached to this post
if ARTICLE_COMPONENT in components:
article = raw_post['content'][ARTICLE_COMPONENT]
# pprint(article, depth=1)
# image_path = article['largeImage']['attributes'][0]['vectorImage']['artifacts'][0]['fileIdentifyingUrlPathSegment']
return out_post
import yaml
for post in posts:
pp = parse_post(post)
pp.created_at.year
pp.created_at.month
yaml_header = yaml.dump({
'title': pp.title,
'date': pp.created_at.isoformat(),
'li-id': pp.id,
'li-url': pp.original_url,
})
dir_container = f"{MD_ORGANIZED_CONTENT_BASE}/{pp.created_at.year}/{pp.created_at.month:02}"
if not os.path.isdir(dir_container):
os.makedirs(dir_container)
with open(f"{dir_container}/{pp.slug}.md", 'w') as f:
f.write("\n".join([
"---",
yaml_header.strip(),
"---",
"",
pp.content
]))

1
janco_posts.json Normal file

File diff suppressed because one or more lines are too long

48108
out_posts.json Normal file

File diff suppressed because it is too large Load diff

48108
out_posts_1.json Normal file

File diff suppressed because it is too large Load diff

48108
out_posts_2.json Normal file

File diff suppressed because it is too large Load diff

441665
out_posts_all_1.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
# this script will look for each markdown with YAML frontmatter header and will rename the file name to the slug from the title in the header
from slugify import slugify
# https://pypi.org/project/python-frontmatter/
import os
import pyaml
import json
import frontmatter
INP_DIR = "./janco_website/true_content/posts"
from pathlib import Path
renamed = 0
for path in Path(INP_DIR).rglob('*.md'):
print(path)
post = frontmatter.load(path)
if post['title'].startswith("CHANGE_ME"):
continue
new_name = slugify.slugify(post['title']) + '.md'
if new_name == path:
print("same")
continue
print("rename")
os.rename(path, path.parent / ('/' + new_name))
renamed += 1
# path, slugify.slugify(post['title'])
print(f"{renamed} files renamed")

65
scrape.py Normal file
View file

@ -0,0 +1,65 @@
from linkedin_api import Linkedin
import os
def fetch_posts(client, public_id=None, urn_id=None, post_count=10):
"""
get_profile_posts: Get profile posts
:param public_id: LinkedIn public ID for a profile
:type public_id: str, optional
:param urn_id: LinkedIn URN ID for a profile
:type urn_id: str, optional
:param post_count: Number of posts to fetch
:type post_count: int, optional
:return: List of posts
:rtype: list
"""
url_params = {
"count": min(post_count, client._MAX_POST_COUNT),
"start": 0,
"q": "memberShareFeed",
"moduleKey": "member-shares:phone",
"includeLongTermHistory": True,
}
if urn_id:
profile_urn = f"urn:li:fsd_profile:{urn_id}"
else:
profile = client.get_profile(public_id=public_id)
profile_urn = profile["profile_urn"].replace(
"fs_miniProfile", "fsd_profile"
)
url_params["profileUrn"] = profile_urn
url = f"/identity/profileUpdatesV2"
res = client._fetch(url, params=url_params)
data = res.json()
if data and "status" in data and data["status"] != 200:
client.logger.info("request failed: {}".format(data["message"]))
return {}
while data and data["metadata"]["paginationToken"] != "":
print(f"got {len(data['elements'])=}")
if len(data["elements"]) >= post_count:
break
pagination_token = data["metadata"]["paginationToken"]
url_params["start"] = url_params["start"] + client._MAX_POST_COUNT
url_params["paginationToken"] = pagination_token
print("new request", url_params)
res = client._fetch(url, params=url_params)
data["metadata"] = res.json()["metadata"]
data["elements"] = data["elements"] + res.json()["elements"]
data["paging"] = res.json()["paging"]
return data["elements"]
# Authenticate using any Linkedin account credentials
api = Linkedin(os.getenv("LINKEDIN_USERNAME"), os.getenv("LINKEDIN_PASSWORD"))
# GET a profile
# profile = api.get_profile('jean-marc-jancovici')
# profile_id = "ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug"
urn_id = "ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug"
posts = fetch_posts(api, urn_id=urn_id, post_count=800)
import json
with open('./out_posts_all_1.json', 'w') as f:
f.write(json.dumps(posts, indent=4))

View file

@ -0,0 +1,65 @@
import json
import yaml
import websocket
import os
BASE_DIR = '../janco_website/content/posts/'
OUTPUT_FILE = './output_shit.json'
files = os.scandir(BASE_DIR)
with open(OUTPUT_FILE, 'w') as of:
of.write("[\n")
def write_result(data):
with open(OUTPUT_FILE, 'a') as of:
of.write(json.dumps(data))
def send_msg(sess, data):
print("Send_msg", data)
sess.send(json.dumps(data))
def talk(sess, inputs):
send_msg(sess, {"type":"generate","inputs":inputs,"max_new_tokens":1,"stop_sequence":"</s>","extra_stop_sequences":["\n\nHuman"],"do_sample":1,"temperature":0.9,"top_k":40})
def collect_response(sess):
all_text = ""
while True:
raw = sess.recv()
print(raw)
res = json.loads(raw)
if 'stop' in res and res['stop']:
return all_text
all_text += res['outputs']
# https://websocket-client.readthedocs.io/en/latest/examples.html
sess = websocket.WebSocket()
sess.connect("ws://chat.petals.ml/api/v2/generate")
# Open model
send_msg(sess, {"type":"open_inference_session","model":"bigscience/bloomz-petals","max_length":1024})
print(sess.recv())
send_msg(sess, {"type":"generate","inputs":"A human talks to a powerful AI that follows the human's instructions.\n\nHuman: Hi!\n\nAI: Hi! How can I help you?</s>Human: Hello\n\nAI:","max_new_tokens":1,"stop_sequence":"</s>","extra_stop_sequences":["\n\nHuman"],"do_sample":1,"temperature":0.9,"top_k":40})
collect_response(sess)
for fname in files:
print("=========")
print(f"opening {fname.path}")
with open(fname.path) as inp_f:
file_content = inp_f.read()
compos = file_content.split('---')
headers = yaml.safe_load(compos[1])
content = compos[2].strip()
print(headers)
print(content)
prefix = "Donnez un titre descriptif résumant ce texte :"
send_msg(sess, {"type":"generate","inputs": "Human: " + prefix + content + "\nAI:","max_new_tokens":1,"stop_sequence":"</s>","extra_stop_sequences":["\n\nHuman"],"do_sample":1,"temperature":0.9,"top_k":40})
generated_title = collect_response(sess)
print(generated_title)
write_result({"on_post_file_path": fname.path, "generated_title": generated_title, "on_post": headers})
with open(OUTPUT_FILE, 'a') as of:
of.write("\n]\n")

View file

@ -0,0 +1,2 @@
[
{"on_post_file_path": "../janco_website/content/posts/2021-05-10-08-17.md", "generated_title": " Plan de transformation de l'\u00e9conomie fran\u00e7aise", "on_post": {"date": "2021-05-10T08:17:53.344000", "li-id": 6797434492945481728, "li-url": "https://www.linkedin.com/posts/jean-marc-jancovici_comment-contribuer-au-plan-de-transformation-activity-6797434492945481728-YglP?utm_source=share&utm_medium=member_desktop", "title": "2021-05-10 08:17"}}{"on_post_file_path": "../janco_website/content/posts/2021-09-12-09-04.md", "generated_title": " Les prix de l'\u00e9lectricit\u00e9 montent en fl\u00e8che. Qu'est-ce qui se passe?", "on_post": {"date": "2021-09-12T09:04:37.616000", "li-id": 6842744738118959104, "li-url": "https://www.linkedin.com/posts/jean-marc-jancovici_les-prix-de-l%C3%A9lectricit%C3%A9-ont-fortement-augment%C3%A9-activity-6842744738118959104-VnLd?utm_source=share&utm_medium=member_desktop", "title": "2021-09-12 09:04"}}

460
tmp.json Normal file
View file

@ -0,0 +1,460 @@
{
"actor": {
"urn": "urn:li:member:101316862",
"image": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "PROFILE_PICTURE",
"miniProfile": {
"firstName": "Jean-Marc",
"lastName": "Jancovici",
"dashEntityUrn": "urn:li:fsd_profile:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"occupation": "Founding Partner, Carbone 4 - President, The Shift project",
"objectUrn": "urn:li:member:101316862",
"entityUrn": "urn:li:fs_miniProfile:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"backgroundImage": {
"com.linkedin.common.VectorImage": {
"artifacts": [
{
"width": 800,
"fileIdentifyingUrlPathSegment": "200_800/0/1623047088606?e=1681948800&v=beta&t=LoNfzUx_oAOOk72H8rcovxufm3ojeyZN-2kh5jNXD1g",
"expiresAt": 1681948800000,
"height": 200
},
{
"width": 1400,
"fileIdentifyingUrlPathSegment": "350_1400/0/1623047088606?e=1681948800&v=beta&t=mIMZE7AxPY31jjVxA6aagUpWg8sYHVdTtMKz28Y9tZU",
"expiresAt": 1681948800000,
"height": 350
}
],
"rootUrl": "https://media.licdn.com/dms/image/C4D16AQFQkQUwXFS8Pg/profile-displaybackgroundimage-shrink_"
}
},
"publicIdentifier": "jean-marc-jancovici",
"picture": {
"com.linkedin.common.VectorImage": {
"artifacts": [
{
"width": 100,
"fileIdentifyingUrlPathSegment": "100_100/0/1621956071842?e=1681948800&v=beta&t=7Rlra5TVZVrH_dL8mO5xBbdGE3WGmkNbLwR5ttc0Og8",
"expiresAt": 1681948800000,
"height": 100
},
{
"width": 200,
"fileIdentifyingUrlPathSegment": "200_200/0/1621956071842?e=1681948800&v=beta&t=TKBiEX7E-NaEd00j4smYvfbncjKD8alhyOi5bAiVEA0",
"expiresAt": 1681948800000,
"height": 200
},
{
"width": 400,
"fileIdentifyingUrlPathSegment": "400_400/0/1621956071842?e=1681948800&v=beta&t=cZI5Kp_eoX797cjLZKJtWf9zCY_WfSimhbmq6cejUbo",
"expiresAt": 1681948800000,
"height": 400
},
{
"width": 800,
"fileIdentifyingUrlPathSegment": "800_800/0/1621956071842?e=1681948800&v=beta&t=5eFGnjR0Od4YDgflWEK-6u7-Vrie2dtGuiWlfGCJ3Hs",
"expiresAt": 1681948800000,
"height": 800
}
],
"rootUrl": "https://media.licdn.com/dms/image/C4D03AQEUVgCmKN3cqQ/profile-displayphoto-shrink_"
}
},
"trackingId": "zfxFwzQcTn6jC0cw3+VeRw=="
}
}
]
},
"supplementaryActorInfo": {
"textDirection": "USER_LOCALE",
"text": " • Following"
},
"name": {
"textDirection": "FIRST_STRONG",
"attributes": [
{
"start": 0,
"length": 19,
"miniProfile": {
"firstName": "Jean-Marc",
"lastName": "Jancovici",
"dashEntityUrn": "urn:li:fsd_profile:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"occupation": "Founding Partner, Carbone 4 - President, The Shift project",
"objectUrn": "urn:li:member:101316862",
"entityUrn": "urn:li:fs_miniProfile:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"backgroundImage": {
"com.linkedin.common.VectorImage": {
"artifacts": [
{
"width": 800,
"fileIdentifyingUrlPathSegment": "200_800/0/1623047088606?e=1681948800&v=beta&t=LoNfzUx_oAOOk72H8rcovxufm3ojeyZN-2kh5jNXD1g",
"expiresAt": 1681948800000,
"height": 200
},
{
"width": 1400,
"fileIdentifyingUrlPathSegment": "350_1400/0/1623047088606?e=1681948800&v=beta&t=mIMZE7AxPY31jjVxA6aagUpWg8sYHVdTtMKz28Y9tZU",
"expiresAt": 1681948800000,
"height": 350
}
],
"rootUrl": "https://media.licdn.com/dms/image/C4D16AQFQkQUwXFS8Pg/profile-displaybackgroundimage-shrink_"
}
},
"publicIdentifier": "jean-marc-jancovici",
"picture": {
"com.linkedin.common.VectorImage": {
"artifacts": [
{
"width": 100,
"fileIdentifyingUrlPathSegment": "100_100/0/1621956071842?e=1681948800&v=beta&t=7Rlra5TVZVrH_dL8mO5xBbdGE3WGmkNbLwR5ttc0Og8",
"expiresAt": 1681948800000,
"height": 100
},
{
"width": 200,
"fileIdentifyingUrlPathSegment": "200_200/0/1621956071842?e=1681948800&v=beta&t=TKBiEX7E-NaEd00j4smYvfbncjKD8alhyOi5bAiVEA0",
"expiresAt": 1681948800000,
"height": 200
},
{
"width": 400,
"fileIdentifyingUrlPathSegment": "400_400/0/1621956071842?e=1681948800&v=beta&t=cZI5Kp_eoX797cjLZKJtWf9zCY_WfSimhbmq6cejUbo",
"expiresAt": 1681948800000,
"height": 400
},
{
"width": 800,
"fileIdentifyingUrlPathSegment": "800_800/0/1621956071842?e=1681948800&v=beta&t=5eFGnjR0Od4YDgflWEK-6u7-Vrie2dtGuiWlfGCJ3Hs",
"expiresAt": 1681948800000,
"height": 800
}
],
"rootUrl": "https://media.licdn.com/dms/image/C4D03AQEUVgCmKN3cqQ/profile-displayphoto-shrink_"
}
},
"trackingId": "zfxFwzQcTn6jC0cw3+VeRw=="
},
"type": "PROFILE_FULLNAME"
}
],
"text": "Jean-Marc Jancovici"
},
"subDescription": {
"textDirection": "USER_LOCALE",
"attributes": [
{
"start": 6,
"length": 1,
"artDecoIcon": "IC_GLOBE_16DP",
"type": "ART_DECO_ICON"
}
],
"text": "11h • ",
"accessibilityText": "11 hours ago"
},
"navigationContext": {
"trackingActionType": "viewMember",
"accessibilityText": "View Jean-Marc Jancovicis profile",
"actionTarget": "https://www.linkedin.com/in/jean-marc-jancovici?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug"
},
"description": {
"textDirection": "USER_LOCALE",
"text": "Founding Partner, Carbone 4 - President, The Shift project"
}
},
"dashEntityUrn": "urn:li:fsd_update:(urn:li:activity:7032115801016938496,MEMBER_SHARES,EMPTY,DEFAULT,false)",
"updateMetadata": {
"urn": "urn:li:activity:7032115801016938496",
"actionsPosition": "ACTOR_COMPONENT",
"updateActions": {
"actions": [
{
"icon": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "SYSTEM_IMAGE",
"systemImage": "SYS_ICN_BOOKMARK_OUTLINE_MEDIUM"
}
]
},
"actionType": "SAVE",
"saveAction": {
"entityUrn": "urn:li:fs_saveAction:(SAVE,urn:li:activity:7032115801016938496)",
"saved": false,
"dashEntityUrn": "urn:li:fsd_saveState:(SAVE,urn:li:activity:7032115801016938496)"
},
"text": "Save"
},
{
"icon": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "SYSTEM_IMAGE",
"systemImage": "SYS_ICN_LINK_MEDIUM"
}
]
},
"actionType": "SHARE_VIA",
"text": "Copy link to post",
"url": "https://www.linkedin.com/posts/jean-marc-jancovici_le-shift-recrute-une-cheffe-de-projet-agriculture-activity-7032115801016938496-lQSy?utm_source=share&utm_medium=member_desktop"
},
{
"icon": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "SYSTEM_IMAGE",
"systemImage": "SYS_ICN_CLEAR_MEDIUM"
}
]
},
"actionType": "UNFOLLOW_MEMBER",
"text": "Unfollow Jean-Marc Jancovici",
"followAction": {
"followTrackingActionType": "followMember",
"followingInfo": {
"followingType": "FOLLOWING",
"entityUrn": "urn:li:fs_followingInfo:urn:li:member:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"dashFollowingStateUrn": "urn:li:fsd_followingState:urn:li:fsd_profile:ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"following": true,
"trackingUrn": "urn:li:member:101316862"
},
"unfollowTrackingActionType": "unfollowMember",
"type": "UNFOLLOW_TOGGLE",
"trackingActionType": "unfollowMember"
},
"confirmationAction": {
"title": {
"text": "Post removed"
},
"description": {
"textDirection": "USER_LOCALE",
"attributes": [],
"text": "You'll no longer see posts from Jean-Marc Jancovici in your feed"
},
"undoable": true
}
},
{
"actionType": "REPORT",
"targetUrn": "urn:li:share:7032115800496848896",
"contentSource": "UGC_POST",
"authorProfileId": "ACoAAAYJ-P4B8XcfHOiVTdmiAyYGfvxBRs3J_Ug",
"authorUrn": "urn:li:member:101316862",
"icon": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "SYSTEM_IMAGE",
"systemImage": "SYS_ICN_REPORT_MEDIUM"
}
]
},
"secondaryAction": {
"icon": {
"accessibilityTextAttributes": [],
"attributes": [
{
"sourceType": "SYSTEM_IMAGE",
"systemImage": "SYS_ICN_VISIBILITY_OFF_MEDIUM"
}
]
},
"actionType": "HIDE_UPDATE",
"targetUrn": "urn:li:activity:7032115801016938496",
"text": "Hide this post",
"confirmationAction": {
"title": {
"textDirection": "USER_LOCALE",
"text": "Post removed"
},
"description": {
"textDirection": "USER_LOCALE",
"text": "You'll no longer see this post in your feed."
},
"undoable": true
}
},
"text": "Report post",
"confirmationAction": {
"title": {
"textDirection": "USER_LOCALE",
"text": "Thank you for your report"
},
"description": {
"textDirection": "USER_LOCALE",
"text": "We appreciate you letting us know"
},
"undoable": false
}
}
],
"entityUrn": "urn:li:fs_updateV2Actions:(urn:li:activity:7032115801016938496,MEMBER_SHARES,EMPTY,-,-)",
"dashEntityUrn": "urn:li:fsd_updateActions:(urn:li:activity:7032115801016938496,MEMBER_SHARES,EMPTY,urn:li:reason:-,urn:li:adCreative:-)"
},
"actionTriggerEnabled": false,
"detailPageType": "FEED_DETAIL",
"shareAudience": "PUBLIC",
"shareUrn": "urn:li:share:7032115800496848896",
"excludedFromSeen": false,
"trackingData": {
"requestId": "b25a7ec3-e28d-48c3-8992-6f2d239bb5ed",
"trackingId": "RG3qysJY+25QguPJBtnAPA=="
}
},
"entityUrn": "urn:li:fs_updateV2:(urn:li:activity:7032115801016938496,MEMBER_SHARES,EMPTY,DEFAULT,false)",
"content": {
"com.linkedin.voyager.feed.render.ArticleComponent": {
"templateType": "DEFAULT",
"urn": "urn:li:article:7508397560141145240",
"swapTitleAndSubtitle": false,
"largeImage": {
"accessibilityTextAttributes": [],
"attributes": [
{
"useCropping": false,
"sourceType": "VECTOR",
"vectorImage": {
"artifacts": [
{
"width": 800,
"fileIdentifyingUrlPathSegment": "800/0/1676589776974?e=1677236400&v=beta&t=LPc9sQwTqe_RKAxA-p-0PgvRKPsbZ9u2APJtFUdR8Ik",
"expiresAt": 1677236400000,
"height": 533
},
{
"width": 815,
"fileIdentifyingUrlPathSegment": "1280_800/0/1676589776974?e=1677236400&v=beta&t=GWvn4lgjCslPvTNHYUSs7C2dPdUQKg45m9kZv5hhw1A",
"expiresAt": 1677236400000,
"height": 543
},
{
"width": 160,
"fileIdentifyingUrlPathSegment": "160/0/1676589776974?e=1677236400&v=beta&t=ULTeCod2tkW1L4eFpuuwmzs-ol35N6ySsc7OcqtmoCU",
"expiresAt": 1677236400000,
"height": 106
},
{
"width": 480,
"fileIdentifyingUrlPathSegment": "480/0/1676589776974?e=1677236400&v=beta&t=-0Lf898wq0wcbhkxvQGq72rtNmuggxYVuUB6KKLBjSI",
"expiresAt": 1677236400000,
"height": 319
}
],
"rootUrl": "https://media.licdn.com/dms/image/sync/D4E27AQENdzDIiQ--jA/articleshare-shrink_"
},
"displayAspectRatio": 0.66625
}
]
},
"saveAction": {
"entityUrn": "urn:li:fs_saveAction:(SAVE,urn:li:article:7508397560141145240)",
"saved": false,
"dashEntityUrn": "urn:li:fsd_saveState:(SAVE,urn:li:article:7508397560141145240)"
},
"subtitle": {
"textDirection": "USER_LOCALE",
"text": "theshiftproject.org • 5 min read"
},
"navigationContext": {
"trackingActionType": "viewLink",
"accessibilityText": "Open article: Le Shift recrute un.e Chef.fe de projet Agriculture ! [CDD 18 mois] by theshiftproject.org",
"actionTarget": "https://theshiftproject.org/article/offre-emploi-chef-projet-agriculture/"
},
"showSmallTitle": false,
"type": "EXTERNAL_FULL",
"title": {
"textDirection": "FIRST_STRONG",
"text": "Le Shift recrute un.e Chef.fe de projet Agriculture ! [CDD 18 mois]"
}
}
},
"commentary": {
"templateType": "DEFAULT",
"translationUrn": "urn:li:fs_translation:(urn:li:share:7032115800496848896,fr)",
"numLines": 3,
"text": {
"textDirection": "FIRST_STRONG",
"text": "Ce n'était pas le secteur le plus travaillé dans le Plan de Transformation de l'Economie Française, et donc le Shift Project a décidé d'y revenir. Car la production et cuisson de nos aliments, en incluant les émissions industrielles amont (fabrication des engrais, des intrants en général, et des machines agricoles), les émissions dans les exploitations, et celles à l'aval (industries agro-alimentaires, transports, emballages, déplacements des consommateurs pour faire les courses, cuisson, etc) c'est un tiers des émissions mondiales, et pas loin du même pourcentage en France.\n\nIl semble donc difficile de dire que nous allons devenir \"neutres\", ce qui suppose de supprimer la quasi-totalié de nos émissions actuelles, sans s'occuper sérieusement de ce secteur. C'est pour cela que The Shift Project se cherche le mouton ou la brebis à 5 pattes (c'est de circonstance) pour piloter la réflexion à venir sur la bonne manière de décarboner notre assiette.\n\nSi faire un petit tour par les locaux de cette association vous tente, à vos CV ! "
},
"originalLanguage": "French",
"dashTranslationUrn": "urn:li:fsd_translation:(urn:li:share:7032115800496848896,fr)"
},
"socialDetail": {
"dashEntityUrn": "urn:li:fsd_socialDetail:(urn:li:activity:7032115801016938496,urn:li:activity:7032115801016938496,urn:li:highlightedReply:-)",
"comments": {
"paging": {
"start": 0,
"count": 0,
"total": 25,
"links": []
},
"elements": []
},
"socialPermissions": {
"dashEntityUrn": "urn:li:fsd_socialPermissions:(urn:li:activity:7032115801016938496,urn:li:fsd_profile:ACoAACezhDYByiG-EGo31qm_ZSu2gSgyNAA1mZM)",
"canPostComments": true,
"entityUrn": "urn:li:fs_socialPermissions:(urn:li:activity:7032115801016938496,urn:li:fs_profile:(ACoAACezhDYByiG-EGo31qm_ZSu2gSgyNAA1mZM,en_US))",
"messagePermission": "PUBLIC",
"canShare": true,
"canReact": true
},
"showPremiumAnalytics": false,
"hideFirstPrompt": true,
"liked": false,
"showShareButton": true,
"totalShares": 0,
"urn": "urn:li:activity:7032115801016938496",
"threadId": "activity:7032115801016938496",
"allowedCommentersScope": "ALL",
"totalSocialActivityCounts": {
"socialDetailEntityUrn": "urn:li:fs_socialDetail:urn:li:activity:7032115801016938496",
"urn": "urn:li:activity:7032115801016938496",
"numComments": 33,
"dashEntityUrn": "urn:li:fsd_socialActivityCounts:urn:li:activity:7032115801016938496",
"reactionTypeCounts": [
{
"count": 243,
"reactionType": "LIKE"
},
{
"count": 9,
"reactionType": "INTEREST"
},
{
"count": 4,
"reactionType": "PRAISE"
},
{
"count": 2,
"reactionType": "APPRECIATION"
},
{
"count": 1,
"reactionType": "MAYBE"
}
],
"entityUrn": "urn:li:fs_socialActivityCounts:urn:li:activity:7032115801016938496",
"numLikes": 259,
"liked": false
},
"entityUrn": "urn:li:fs_socialDetail:urn:li:activity:7032115801016938496",
"commentingDisabled": false,
"likes": {
"paging": {
"start": 0,
"count": 0,
"total": 259,
"links": []
},
"elements": []
}
}
}